package com.alibaba.cirtus.ots.application.adapter.ability.facade.serviceV2.sap;

import com.alibaba.acm.shaded.com.google.common.collect.Maps;
import com.alibaba.cirtus.ots.application.adapter.ability.strategy.StrategyQueryAbility;
import com.alibaba.cirtus.ots.application.adapter.ability.utils.*;
import com.alibaba.citrus.cr.common.enums.ordercenter.AsyncMessageEventEnum;
import com.alibaba.citrus.cr.common.enums.ordercenter.SalesOrderPushStatusEnum;
import com.alibaba.citrus.ots.common.annotation.ProcessInvoker;
import com.alibaba.citrus.ots.common.exception.FacadeException;
import com.alibaba.citrus.ots.common.lock.SaleRedisLock;
import com.alibaba.citrus.ots.common.util.IntegrateUtils;
import com.alibaba.citrus.ots.common.util.JsonUtil;
import com.alibaba.citrus.ots.common.util.SapAndCrmFieldDealUtils;
import com.alibaba.cz.base.tool.Nullable;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.lattice2.epoch.middleware.cache.runtime.service.EpochCacheService;
import com.alibaba.lattice2.epoch.middleware.mq.runtime.EpochMessageService;
import com.alibaba.lattice2.epoch.sdk.model.Result;
import com.epoch.app.bcorder.model.dto.ScItemSDO;
import com.epoch.app.bcorder.model.dto.SearchScItemByDBWhenDegradedRequest;
import com.epoch.app.bcorder.service.BaseDataService;
import com.epoch.app.bcots.contants.BcOtsConstants;
import com.epoch.app.crb2btradecenter.domain.order.dto.LoadOrderListRequest;
import com.epoch.app.crb2btradecenter.domain.order.dto.LoadOrderRequest;
import com.epoch.app.crb2btradecenter.domain.order.dto.QueryByOuterOrderIdsRequest;
import com.epoch.app.crb2btradecenter.domain.order.model.Order;
import com.epoch.app.crb2btradecenter.domain.order.service.OrderService;
import com.epoch.app.crb2btradecenter.domain.orderline.dto.OrderLineLoadListRequest;
import com.epoch.app.crb2btradecenter.domain.orderline.model.OrderLine;
import com.epoch.app.crb2btradecenter.domain.orderline.service.OrderLineService;
import com.epoch.app.crb2btradecenter.enums.OrderStatus;
import com.epoch.app.crunifiedinventory.api.allocateorderwrite.service.AllocateOrderWriteService;
import com.epoch.app.crunifiedinventory.api.consignmentorderwrite.service.ConsignmentOrderWriteService;
import com.epoch.app.crunifiedinventory.consignmentorder.model.ConsignmentOrder;
import com.epoch.app.crunifiedinventory.consignmentorder.service.ConsignmentOrderService;
import com.epoch.app.crunifiedinventory.consignmentorderline.model.ConsignmentOrderLine;
import com.epoch.app.crunifiedinventory.consignmentorderline.service.ConsignmentOrderLineService;
import com.epoch.app.crunifiedinventory.consignmentorderquery.service.ConsignmentOrderQueryService;
import com.epoch.app.crunifiedinventory.domain.allocateorder.dto.AllocateOrderLoadListRequest;
import com.epoch.app.crunifiedinventory.domain.allocateorder.model.AllocateOrder;
import com.epoch.app.crunifiedinventory.domain.allocateorder.service.AllocateOrderService;
import com.epoch.app.crunifiedinventory.dto.request.AllocateOrderDeliveryScItemDTO;
import com.epoch.app.crunifiedinventory.dto.request.ConsignmentOrderWriteCreateRequest;
import com.epoch.app.crunifiedinventory.dto.response.AllocateOrderDeliveryResponse;
import com.epoch.app.crunifiedinventory.model.dto.*;
import com.epoch.app.crunifiedinventory.sdo.ConsignmentOrderSDO;
import com.epoch.app.crunifiedinventory.sdo.enums.ReasonForRejectionEnum;
import com.epoch.app.crunifiedinventory.service.CrUnifiedInventoryService;
import com.epoch.app.mnordercenter.model.dto.CommonAsyncMessageResponse;
import com.epoch.app.mnordercenter.model.dto.PushOrderInfoToMnSideRequestOrderInfo;
import com.epoch.app.otsapplicationadaptersdk.contants.OtsApplicationAdapterSdkConstants;
import com.epoch.app.otsapplicationadaptersdk.model.dto.*;
import com.epoch.app.otsapplicationadaptersdk.model.enums.RetryStatus;
import com.epoch.app.otsapplicationadaptersdk.model.enums.SapApiCode;
import com.epoch.app.otsapplicationadaptersdk.sap.*;
import com.epoch.app.otsapplicationadaptersdk.sapretry.model.SapRetry;
import com.epoch.app.otsapplicationadaptersdk.sapretry.service.SapRetryService;
import com.epoch.app.otsapplicationadaptersdk.sapretrywrite.service.SapRetryWriteService;
import com.epoch.app.otsapplicationadaptersdk.sapv2.mnsapif017v2.service.MnSapIf017V2Service;
import com.epoch.app.otsapplicationadaptersdk.service.OtsApplicationAdapterSdkService;
import com.epoch.app.otsunifiedinventory.model.dto.WmsSDO;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Primary;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import tools.Pair;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author
 * @date 2021/10/12
 * @Description sap请求平台同步交货单创建
 */
@Component
@Primary
public class MnSapIf017V2ServiceImpl implements MnSapIf017V2Service {
    private final Log log = Log.getLogger(MnSapIf017V2ServiceImpl.class);
    @Resource
    private ConsignmentOrderQueryService consignmentOrderQueryService;
    @Resource
    private ConsignmentOrderWriteService consignmentOrderWriteService;
    @Resource
    private AllocateOrderWriteService allocateOrderWriteService;
    @Resource
    private SapRetryWriteService sapRetryWriteService;
    @Resource
    private AllocateOrderService allocateOrderService;
    @Resource
    private OrderService orderService;
    @Resource
    private EpochCacheService epochCacheService;
    @Resource
    private CrUnifiedInventoryService crUnifiedInventoryService;
    @Resource
    private OrderLineService orderLineService;
    @Resource
    private ConsignmentOrderService consignmentOrderService;
    @Resource
    private ConsignmentOrderLineService consignmentOrderLineService;
    @Resource
    private SapRetryService sapRetryService;
    @Resource
    private BaseDataService baseDataService;
    @Resource
    private EpochMessageService messageService;
    @Resource
    private StrategyQueryAbility strategyQueryAbility;
    @Resource
    private OtsApplicationAdapterSdkService otsApplicationAdapterSdkService;
    @Autowired
    private HttpUtils httpUtils;

    private static final String SPEC_ORG = "1171";
    private static final String DELIVERY_ORDER_CACHE_KEY = "DELIVERY_ORDER_CACHE_KEY_";
    public static final String SAP_SYNC = "sapSync:";
    private static final String LOCK_PREFIX = "saleLock:";
    private static final String DELIVERY_ORDER_LOCK = "DELIVERY_ORDER_LOCK_";
    private static final List<String> saleOrderExtList = Lists.newArrayList("ZORO", "ZORA", "ZRE5");
    //退货销售单类型 不预占库存
    private final static List<String> returnGoodsExtList = Lists.newArrayList("ZRE2", "ZRE3");
    public static final String EXCHANGE = "exchange";
    private static final String EXCHANGE_ORDER_TYPE = "ZCH2";
    private static final Integer MAX_PAGE_SIZE = 1000;
    private static final String CONSIGNMENT_ORDER_SYNC = "CONSIGNMENT_ORDER_SYNC_";
    private static final String SPLIT = ".";

    //设置sap过期时间为
    private static final Long SAP_TIMESTAMP_CACHE_EXPIRE = 60 * 60 * 24 * 100L;
    @Value("${ots.checkTimestamp:0}")
    private boolean checkTimestamp;

    @Override
    @ProcessInvoker(remark = "MnSapIf017V2Service", errorCode = "OTS-02-007-00-16-999", printLog = true)
    public MnSapCommResponse externalSyncDeliveryOrder(MnSapIf017Request mnSapIf017Request) {
        log.info("MnSapIf017V2ServiceImpl#externalSyncDeliveryOrder mnSapIf017Request={}", JSONObject.toJSONString(mnSapIf017Request));
        boolean isInPilotScope = isInPilotScope(mnSapIf017Request.getData().get(0));
        log.info("MnSapIf017V2ServiceImpl#externalSyncDeliveryOrder isInPilotScope={}", isInPilotScope);
        if (isInPilotScope) {
            try {
                return externalSyncDeliveryOrderV2(mnSapIf017Request);
            } catch (Exception e) {
                log.error("externalSyncDeliveryOrderV2 error.", e);
            }
        }
        MnSapCommResponse mnSapCommResponse = new MnSapCommResponse();

        // Try to get from mogodb if null
        if (mnSapIf017Request == null) {
            mnSapIf017Request = IntegrateUtils.safeGetMessageObject(MnSapIf017Request.class);
        }

        mnSapCommResponse.setMessageId(mnSapIf017Request.getMessageHeader().getMessageId());
        mnSapCommResponse.setInterfacePath(mnSapIf017Request.getMessageHeader().getInterfacePath());
        List<String> outSourceOrderIds=new ArrayList<>();
        List<MnSapCommSDO> respData = new ArrayList<>();
        for (MnSapIf017SDO datum : mnSapIf017Request.getData()) {
            // 包括通过013创建的单子 sap报文里的订单id转换成内部主键id  sap: 1开头 中间补0  总长度10
            datum.setOuterSalesOrderId(CodeUtil.convertTradeOrderId(datum.getOuterSalesOrderId()));
            datum.setOuterStoOrderId(CodeUtil.convertTradeOrderId(datum.getOuterStoOrderId()));
            outSourceOrderIds.add(datum.getOuterSalesOrderId());
//            String lockKey = DELIVERY_ORDER_LOCK + SapAndCrmFieldDealUtils.generateIdField(datum.getDeliveryOrderId());
            //交货单集成接口和销售单有并发时序问题，使用同一个redis lock来处理
            String outOrderId = SapAndCrmFieldDealUtils.generateIdField(StringUtils.isNotBlank(datum.getSalesOrderId()) ? datum.getSalesOrderId() : datum.getStoOrderId());
            String lockKey = SAP_SYNC + outOrderId;
            try (SaleRedisLock lock = new SaleRedisLock(BcOtsConstants.REDIS_CACHE_CODE(), lockKey,
                    2 * 60 * 1000, 10 * 60 * 1000)) {
                if (!lock.lock()) {
                    //写入重试表
                    saveSapRetry(mnSapIf017Request, "获取分布式锁错误");
                    return ResponseUtil.fail(mnSapIf017Request, "获取分布式锁错误");
                }
                log.info("MnSapIf017V2ServiceImpl_getLock");
                if (checkTimestamp) {
                    String check = ResponseUtil.check(datum.getExt1());
                    if (StringUtils.isNotBlank(check)) {
//                    saveSapRetry(mnSapIf017Request,check);
                        MnSapCommSDO mnSapCommSDO = new MnSapCommSDO();
                        mnSapCommSDO.setStatus("E");
                        mnSapCommSDO.setMessage(check);
                        mnSapCommSDO.setHeaderKey(datum.getHeaderKey());
                        List<MnSapCommDetail> commDetails = new ArrayList<>();
                        MnSapCommDetail mnSapCommDetail = new MnSapCommDetail();
                        mnSapCommDetail.setStatus("E");
                        mnSapCommDetail.setMessage(check);
//                mnSapCommDetail.setItemKey(item.getItem_key());
                        commDetails.add(mnSapCommDetail);
                        mnSapCommSDO.setItem(commDetails);
                        respData.add(mnSapCommSDO);
                        mnSapCommResponse.setData(respData);
                        return mnSapCommResponse;
                    }
                    boolean checkModifierTime = checkModifierTime(datum);
                    if (!checkModifierTime) {
                        //时间戳校验不通过需要抛错 放入重试表
                        saveSapRetry(mnSapIf017Request, "当前修改时间早于上一次 不允许更新");
                        MnSapCommSDO mnSapCommSDO = new MnSapCommSDO();
                        mnSapCommSDO.setStatus("E");
                        mnSapCommSDO.setMessage("当前修改时间早于上一次 不允许更新");
                        mnSapCommSDO.setHeaderKey(datum.getHeaderKey());
                        List<MnSapCommDetail> commDetails = new ArrayList<>();
                        MnSapCommDetail mnSapCommDetail = new MnSapCommDetail();
                        mnSapCommDetail.setStatus("E");
                        mnSapCommDetail.setMessage("当前修改时间早于上一次 不允许更新");
//                mnSapCommDetail.setItemKey(item.getItem_key());
                        commDetails.add(mnSapCommDetail);
                        mnSapCommSDO.setItem(commDetails);
                        respData.add(mnSapCommSDO);
                        mnSapCommResponse.setData(respData);
                        return mnSapCommResponse;
                    } else {
                        //校验通过就要放入时间戳
//                    cache(datum.getDeliveryOrderId(),datum.getExt());
                    }

                }

                //销售单是否需要预占库存
                boolean occupyFlg = false;
                String salesOrderId = null;
                String salesOrderBizNo = null;

                ConsignmentOrderWriteCreateRequest request = new ConsignmentOrderWriteCreateRequest();
                request.setOuterDeliveryOrderId(SapAndCrmFieldDealUtils.generateIdField(datum.getDeliveryOrderId()));
                request.setOuterSalesOrderId(SapAndCrmFieldDealUtils.generateIdField(datum.getSalesOrderId()));
                request.setSalesOrderId(SapAndCrmFieldDealUtils.generateIdField(datum.getOuterSalesOrderId()));
                request.setOuterStoOrderId(SapAndCrmFieldDealUtils.generateIdField(datum.getStoOrderId()));
                request.setCreator(SapAndCrmFieldDealUtils.generateIdField(datum.getCreator()));
                request.setModifier(SapAndCrmFieldDealUtils.generateIdField(datum.getModifier()));
//            BaselineGetOrganizationByOutCodesRequest orgRequset = new BaselineGetOrganizationByOutCodesRequest();
//            orgRequset.setOutCodes(Lists.newArrayList(SapAndCrmFieldDealUtils.generateIdField(datum.getSalesOrgId())));
//            Map saleOrgMap = externalSyncDeliveryOrder$callAPI2(orgRequset);
//            JSONArray saleJsonArray = JSONObject.parseObject(JSONObject.toJSONString(saleOrgMap)).getJSONArray("result");
//            if (CollectionUtils.isEmpty(saleJsonArray)) {
//                List<MnSapCommSDO> sdos = new ArrayList<>();
//                MnSapCommSDO mnSapCommSDO = new MnSapCommSDO();
//                mnSapCommSDO.setStatus("E");
//                mnSapCommSDO.setMessage("销售组织信息转换失败");
//                mnSapCommSDO.setErrCode("999");
//                mnSapCommSDO.setHeaderKey(datum.getHeaderKey());
//                sdos.add(mnSapCommSDO);
//                mnSapCommResponse.setData(sdos);
//                return mnSapCommResponse;
//            }
//            JSONObject organizationSDO = saleJsonArray.getJSONObject(0).getJSONObject("organizationSDO");
//            request.setSalesOrgId(organizationSDO.getString("id"));
                request.setSalesOrgId(datum.getSalesOrgId());
                request.setStoOrderId(SapAndCrmFieldDealUtils.generateIdField(datum.getOuterStoOrderId()));
                request.setCreator(datum.getCreator());
                request.setCreatDate(SapAndCrmFieldDealUtils.toDate(datum.getCreatDate()));
                request.setModifier(datum.getModifier());
                request.setModifidDate(SapAndCrmFieldDealUtils.toDate(datum.getModifidDate()));
                request.setDeliveryDate(SapAndCrmFieldDealUtils.toDate(datum.getDeliveryDate()));
                request.setFeatures(datum.getFeatures());

                //013接口会同步特殊的销售单，判断ext=ZORO且销售组织是1171的交货单，修改为销售订单类型的交货单
                if ((StringUtils.isNotBlank(datum.getExt()) && saleOrderExtList.contains(datum.getExt())) && (
                        StringUtils.isNotBlank(datum.getSalesOrgId()) && SPEC_ORG.equalsIgnoreCase(datum.getSalesOrgId())
                )) {
                    request.setOuterSalesOrderId(SapAndCrmFieldDealUtils.generateIdField(datum.getStoOrderId()));
                }

                //开始处理明细
                MnSapCommSDO mnSapCommSDO = new MnSapCommSDO();
                mnSapCommSDO.setStatus("S");
                mnSapCommSDO.setMessage("成功");
                mnSapCommSDO.setHeaderKey(datum.getHeaderKey());
                List<MnSapCommDetail> details = new ArrayList<>();
                List<AllocateOrderDeliveryScItemDTO> scItemDTOList = Lists.newArrayList();
                List<ConsignmentOrderLineRequest> collect = new ArrayList<>();
                for (MnSapIf017Detail item : datum.getItems()) {
                    ConsignmentOrderLineRequest lineRequest = new ConsignmentOrderLineRequest();
                    lineRequest.setOuterOrderLineId(SapAndCrmFieldDealUtils.generateIdField(item.getOrderLineId()));
                    lineRequest.setOuterSoLineId(SapAndCrmFieldDealUtils.generateIdField(item.getSoLineId()));
                    lineRequest.setSoLineId(SapAndCrmFieldDealUtils.generateIdField(item.getOuterSoLineId()));
                    lineRequest.setOuterStoLineId(SapAndCrmFieldDealUtils.generateIdField(item.getStoLineId()));
                    lineRequest.setStoLineId(SapAndCrmFieldDealUtils.generateIdField(item.getStoLineId()));
                    if ((StringUtils.isNotBlank(datum.getExt()) && saleOrderExtList.contains(datum.getExt())) && (
                            StringUtils.isNotBlank(datum.getSalesOrgId()) && SPEC_ORG.equalsIgnoreCase(datum.getSalesOrgId())
                    )) {
                        lineRequest.setOuterSoLineId(SapAndCrmFieldDealUtils.generateIdField(item.getStoLineId()));
                    }
                    String scItemId = null;
                    try {
                        SearchScItemByDBWhenDegradedRequest searchScItemByDBWhenDegradedRequest = new SearchScItemByDBWhenDegradedRequest();
                        Map<Object, Object> objectObjectMap = Maps.newLinkedHashMap();
                        objectObjectMap.put("outerId", SapAndCrmFieldDealUtils.generateScItemIdField(item.getScItemId()));
                        //需要查出货品被禁用的 1启用 -1禁用
                        objectObjectMap.put("statusList", Lists.newArrayList(1, -1));
                        searchScItemByDBWhenDegradedRequest.setSearchReqDTO(objectObjectMap);
                        Result<List<ScItemSDO>> listResult = baseDataService.searchScItemByDBWhenDegraded(searchScItemByDBWhenDegradedRequest);
                        if (Objects.nonNull(listResult) && CollectionUtils.isNotEmpty(listResult.getResult())) {
                            scItemId = listResult.getResult().get(0).getScItemId();
                            ;
                        }
                        //2022.05.19 因为定时器里用callAPI报错了 会引起未知的问题 所以callAPI放弃使用
                    } catch (Throwable e) {
                        log.error("MnSapIf017ServiceImpl_scItemConvertError", e);
                    }
                    if (StringUtils.isBlank(scItemId)) {
                        log.error("MnSapIf017ServiceImpl_scItemConvertError:{}", item.getScItemId());
                        mnSapCommSDO.setStatus("E");
                        mnSapCommSDO.setMessage(item.getScItemId() + " 货品编码转换失败");
                        mnSapCommSDO.setHeaderKey(datum.getHeaderKey());
                        List<MnSapCommDetail> commDetails = new ArrayList<>();
                        MnSapCommDetail mnSapCommDetail = new MnSapCommDetail();
                        mnSapCommDetail.setStatus("E");
                        mnSapCommDetail.setMessage(item.getScItemId() + " 货品编码转换失败");
                        mnSapCommDetail.setItemKey(item.getItem_key());
                        commDetails.add(mnSapCommDetail);
                        mnSapCommSDO.setItem(commDetails);
                        respData.add(mnSapCommSDO);
                        mnSapCommResponse.setData(respData);
                        saveSapRetry(mnSapIf017Request, item.getScItemId() + " 货品编码转换失败");
                        return mnSapCommResponse;
                    }

//                JSONObject scItemJson = scItemJsonArray.getJSONObject(0);
                    lineRequest.setScItemId(scItemId);
                    lineRequest.setQty(item.getQty());
                    lineRequest.setPodStatus(item.getPodStatus());
                    lineRequest.setPodQty(item.getPodQty());
                    lineRequest.setFactoryCode(item.getFactoryCode());
                    lineRequest.setInventoryCode(item.getInventoryCode());
                    lineRequest.setSaleUnit(item.getSaleUnit());
                    lineRequest.setBasicQuantity(item.getBasicQuantity());
                    collect.add(lineRequest);

                    AllocateOrderDeliveryScItemDTO scItemDTO = new AllocateOrderDeliveryScItemDTO();
                    scItemDTO.setScItemCode(subStringScItmCode(item.getScItemId()));
                    scItemDTO.setDeliveryQuantity(item.getQty());
                    //文档 和数据库 是反着来的 此处指报文里的stoLineId为调拨单的外部行号 去掉前缀0
                    scItemDTO.setOutAllocateOrderLineId(InfoUtil.deleteZeroPrefix(item.getStoLineId()));
//                scItemDTO.setOutAllocateOrderLineId(item.getOuterStoLineId());
                    scItemDTOList.add(scItemDTO);

                    MnSapCommDetail mnSapCommDetail = new MnSapCommDetail();
                    mnSapCommDetail.setStatus("S");
                    mnSapCommDetail.setMessage("成功");
                    mnSapCommDetail.setItemKey(item.getItem_key());
                    details.add(mnSapCommDetail);
                    mnSapCommSDO.setItem(details);
                }
                respData.add(mnSapCommSDO);

                request.setConsignmentOrderLineRequest(collect);
                //2022.05.18 如果查询不到调拨单/销售单 那么就需要重试
                if (StringUtils.isNotBlank(request.getOuterSalesOrderId())) {
                    LoadOrderListRequest loadOrderListRequest = new LoadOrderListRequest();
                    //此处不能去0 因为销售单里的外部单号存了0
                    loadOrderListRequest.setOuterOrderId(request.getOuterSalesOrderId());
                    Result<List<Order>> listResult = orderService.loadOrderList(loadOrderListRequest);
                    if (Objects.isNull(listResult) || CollectionUtils.isEmpty(listResult.getResult())) {
                        saveSapRetry(mnSapIf017Request, "交货单查询不到销售单");
                        return ResponseUtil.fail(mnSapIf017Request, "交货单查询不到销售单");
                    }

                    //是销售单需要进行库存预占逻辑
                    occupyFlg = true;
                    Order order = listResult.getResult().get(0);
                    salesOrderId = String.valueOf(order.getId());
                    salesOrderBizNo=order.getOrderBizId();

                } else if (StringUtils.isNotBlank(datum.getStoOrderId())) {
                    AllocateOrderLoadListRequest allocateOrderLoadListRequest = new AllocateOrderLoadListRequest();
                    allocateOrderLoadListRequest.setOutAllocateOrderId(datum.getStoOrderId());
                    Result<List<AllocateOrder>> loadAllocateOrderList = allocateOrderService.loadAllocateOrderList(allocateOrderLoadListRequest);
                    if (loadAllocateOrderList == null || CollectionUtils.isEmpty(loadAllocateOrderList.getResult())) {
                        // 查不到调拨单，再查销售单
                        LoadOrderListRequest loadOrderListRequest = new LoadOrderListRequest();
                        loadOrderListRequest.setOuterOrderId(request.getOuterStoOrderId());
                        log.info("017 loadOrderList req={}", JSON.toJSONString(loadOrderListRequest));
                        Result<List<Order>> listResult = orderService.loadOrderList(loadOrderListRequest);
                        log.info("017 loadOrderList res={}", JSON.toJSONString(listResult));
                        if (Objects.isNull(listResult) || CollectionUtils.isEmpty(listResult.getResult())) {
                            log.error("stoOrderId={} not found in sales or allocate order",datum.getStoOrderId());
                            saveSapRetry(mnSapIf017Request, "交货单查询不到销售单和调拨单");
                            return ResponseUtil.fail(mnSapIf017Request, "交货单查询不到销售单和调拨单");
                        } else {
                            // 修正字段的值，sto字段给so字段赋值
                            request.setOuterSalesOrderId(request.getOuterStoOrderId());
                            request.setOuterStoOrderId(null);
                            request.setSalesOrderId(request.getStoOrderId());
                            request.setStoOrderId(null);
                            for (ConsignmentOrderLineRequest line : request.getConsignmentOrderLineRequest()) {
                                line.setOuterSoLineId(line.getOuterStoLineId());
                                line.setOuterStoLineId(null);
                                line.setSoLineId(line.getStoLineId());
                                line.setStoLineId(null);
                            }
                        }
                    }
                    //AllocateOrder allocateOrder = loadAllocateOrderList.getResult().get(0);
                    //if (skip017(allocateOrder)) {
                    //    log.info("MnSapIf017V2Service skip allocateOrderId={},fulfillmentTypeCode={}",
                    //        allocateOrder.getId(), allocateOrder.getFulfillmentTypeCode());
                    //    return ResponseUtil.success(mnSapIf017Request);
                    //}
                }

                boolean isNeedHandleOccupy = isNeedHandleOccupy(datum);
                //是否删除过交货单, 如果删除过交货单, 新交货单来时需要重新预占
                boolean hasDelConsignmentOrder = false;

                //交货单落库前 查库里是否有交货单 (第一次创建交货单 库里没有交货单 需要查询销售单明细 后面作为封装释放库存请求源)
                List<ConsignmentOrder> loadConsignmentOrderList = null;
                List<ConsignmentOrderLine> consignmentOrderLines = null;
                List<OrderLine> orderLineList = null;
                Order targetOrder = null;
                if (isNeedHandleOccupy) {
                    log.info("MnSapIf017V2ServiceImpl_isSaleOrder_true");
                    try {
                        ConsignmentOrderLoadListRequest consignmentOrderLoadListRequest = new ConsignmentOrderLoadListRequest();
                        //去掉前缀0
                        consignmentOrderLoadListRequest.setOuterDeliveryOrderId(SapAndCrmFieldDealUtils.generateIdField(datum.getDeliveryOrderId()));
                        consignmentOrderLoadListRequest.setStatus(1);
                        Result<List<ConsignmentOrder>> loadConsignmentOrderListResult = consignmentOrderService.loadConsignmentOrderList(consignmentOrderLoadListRequest);
                        log.info("MnSapIf017V2ServiceImpl_loadConsignmentOrder:{}", JSON.toJSONString(loadConsignmentOrderListResult));
                        if (!Objects.isNull(loadConsignmentOrderListResult) && CollectionUtils.isNotEmpty(loadConsignmentOrderListResult.getResult())) {
                            ConsignmentOrder consignmentOrder = loadConsignmentOrderListResult.getResult().get(0);
                            ConsignmentOrderLineLoadListRequest consignmentOrderLineLoadListRequest = new ConsignmentOrderLineLoadListRequest();
                            consignmentOrderLineLoadListRequest.setConsignmentOrderId(consignmentOrder.getId().toString());
                            consignmentOrderLineLoadListRequest.setLimit(MAX_PAGE_SIZE);
                            Result<List<ConsignmentOrderLine>> listResult = consignmentOrderLineService.loadConsignmentOrderLineList(consignmentOrderLineLoadListRequest);
                            log.info("MnSapIf017V2ServiceImpl_loadConsignmentOrder_LineList:{}", JSON.toJSONString(listResult));
                            if (listResult != null && CollectionUtils.isNotEmpty(listResult.getResult())) {
                                consignmentOrderLines = listResult.getResult();
                            }
                        }

                        //判断这个销售单是否是第一次来交货单,如果之前有删除过交货单 需要重新反向预占库存;反向预占 是以当前交货单的明细来占用
                        ConsignmentOrderLoadListRequest checkListRequest = new ConsignmentOrderLoadListRequest();
                        checkListRequest.setOuterSalesOrderId(request.getOuterSalesOrderId());
                        //013接口会同步特殊的销售单，判断ext=ZORO且销售组织是1171的交货单，修改为销售订单类型的交货单
                        if ((StringUtils.isNotBlank(datum.getExt()) && saleOrderExtList.contains(datum.getExt())) && (
                                StringUtils.isNotBlank(datum.getSalesOrgId()) && SPEC_ORG.equalsIgnoreCase(datum.getSalesOrgId())
                        )) {
                            checkListRequest.setOuterStoOrderId(datum.getStoOrderId());
                        }
                        checkListRequest.setStatus(0);
                        Result<List<ConsignmentOrder>> listResult = consignmentOrderService.loadConsignmentOrderList(checkListRequest);
                        if (listResult != null && CollectionUtils.isNotEmpty(listResult.getResult())) {
                            //有删除过交货单 判断差量时 需要重新预占现有的交货单
                            log.info("MnSapIf017V2ServiceImpl_hasDelConsignmentOrder_true");
                            hasDelConsignmentOrder = true;
                        }
                        LoadOrderRequest loadOrderRequest = new LoadOrderRequest();
                        loadOrderRequest.setId(salesOrderId);
                        Order order = orderService.loadOrder(loadOrderRequest);
                        targetOrder = order;
                        if (CollectionUtils.isEmpty(consignmentOrderLines)) {
                            if (order != null) {
                                //换货只取换货的行 且非关闭的
                                if (EXCHANGE_ORDER_TYPE.equals(order.getOrderType())) {
                                    OrderLineLoadListRequest orderLineLoadListRequest = new OrderLineLoadListRequest();
                                    orderLineLoadListRequest.setMainOrderId(salesOrderId);
                                    orderLineLoadListRequest.setLimit(MAX_PAGE_SIZE);
                                    Result<List<OrderLine>> lineResult = orderLineService.loadOrderLineList(orderLineLoadListRequest);
                                    if (lineResult != null && CollectionUtils.isNotEmpty(lineResult.getResult())) {
                                        orderLineList = lineResult.getResult().stream().filter(x -> EXCHANGE.equals(x.getOrderLineTag()) &&
                                                        !ReasonForRejectionEnum.Z1.getCode().equals(x.getRefuseReasonCode()))
                                                .collect(Collectors.toList());
                                    }
                                } else {
                                    OrderLineLoadListRequest orderLineLoadListRequest = new OrderLineLoadListRequest();
                                    orderLineLoadListRequest.setMainOrderId(salesOrderId);
                                    orderLineLoadListRequest.setLimit(MAX_PAGE_SIZE);
                                    Result<List<OrderLine>> lineResult = orderLineService.loadOrderLineList(orderLineLoadListRequest);
                                    if (lineResult != null && CollectionUtils.isNotEmpty(lineResult.getResult())) {
                                        orderLineList = lineResult.getResult().stream().filter(x -> !ReasonForRejectionEnum.Z1.getCode().equals(x.getRefuseReasonCode()))
                                                .collect(Collectors.toList());
                                    }

                                }

                            }
                        }
                    } catch (Exception e) {
                        //error
                        log.error("MnSapIf017V2ServiceImpl_loadConsignmentOrderList_error", e);
                    }
                }

                ////更新出入库单的交货单号
                //try {
                //    QueryWmsOrderByOtherOrderRequest queryWmsOrderByOtherOrderRequest = new QueryWmsOrderByOtherOrderRequest();
                //    queryWmsOrderByOtherOrderRequest.setBizOrderId(salesOrderBizNo);
                //    queryWmsOrderByOtherOrderRequest.setContainSubOrders(Boolean.TRUE);
                //    log.info("017 queryInOutBoundByDelivery request:{}", JSON.toJSONString(queryWmsOrderByOtherOrderRequest));
                //    Result<WarehousingOrderDTOResponse> result = otsApplicationAdapterSdkService.queryWmsOrderByOtherOrder(queryWmsOrderByOtherOrderRequest);
                //    log.info("017 queryInOutBoundByDelivery response:{}", JSON.toJSONString(result));
                //    if (Objects.nonNull(result)&&Objects.nonNull(result.getResult())&&CollectionUtils.isNotEmpty(result.getResult().getWarehousingOrders())){
                //        List<WarehousingOrderDTO> warehousingOrders = result.getResult().getWarehousingOrders();
                //        for (WarehousingOrderDTO warehousingOrder : warehousingOrders) {
                //            warehousingOrder.setDeliveryOrderId(datum.getDeliveryOrderId());
                //            warehousingOrder.setPrevWmsOrderId(datum.getDeliveryOrderId());
                //            warehousingOrder.setFeatureMap(null);
                //            HashMap<String, String> soLineNoToDelivery = new HashMap<>();
                //            for (MnSapIf017Detail item : datum.getItems()) {
                //                soLineNoToDelivery.put(InfoUtil.deleteZeroPrefix(item.getOuterSoLineId()),InfoUtil.deleteZeroPrefix(item.getOrderLineId()));
                //            }
                //
                //            List<WmsOrderDetailDTO> wmsOrderDetailList = warehousingOrder.getWmsOrderDetailList();
                //            for (WmsOrderDetailDTO wmsOrderDetailDTO : wmsOrderDetailList) {
                //                String bizSubOrderId = wmsOrderDetailDTO.getBizSubOrderId();
                //                if (soLineNoToDelivery.containsKey(bizSubOrderId)){
                //                    wmsOrderDetailDTO.setDeliverySubOrderId(soLineNoToDelivery.get(bizSubOrderId));
                //                }
                //            }
                //            log.info("017 updateWmsOrderInner request:{}", JSON.toJSONString(warehousingOrder));
                //
                //            Result<Void> updateResult = otsApplicationAdapterSdkService.updateWmsOrderInner(warehousingOrder);
                //
                //            log.info("017 updateWmsOrderInner request:{}", JSON.toJSONString(updateResult));
                //
                //        }
                //    }
                //}catch (Exception e){
                //    log.error("更新出入库失败!",e);
                //}

                log.info("MnSapIf017V2ServiceImpl_create_start");
                try {
                    consignmentOrderWriteService.create(request);
                    log.info("MnSapIf017V2ServiceImpl_create_end");
                } catch (Throwable e) {
                    log.error("MnSapIf017V2ServiceImpl_create_error", e);
                    saveSapRetry(mnSapIf017Request, "交货单更新异常");
                    return ResponseUtil.fail(mnSapIf017Request, "交货单更新异常");
                }

                // TBD 这里的异常处理和返回值处理需要优化，除非确定是弱依赖，
                try {
                    AllocateOrderDeliveryRequest allocateOrderDeliveryRequest = new AllocateOrderDeliveryRequest();
                    allocateOrderDeliveryRequest.setCode(datum.getOuterStoOrderId());
                    if (StringUtils.isNotBlank(datum.getStoOrderId())) {
                        allocateOrderDeliveryRequest.setOutAllocateOrderId(datum.getStoOrderId());
                    }
                    allocateOrderDeliveryRequest.setDeliveryDate(datum.getDeliveryDate());
                    //实际用这个作为交货日期
                    allocateOrderDeliveryRequest.setCreateDate(datum.getCreatDate());
                    //更改调拨单的交货数量
                    allocateOrderDeliveryRequest.setDeliveryScItemDTOList(scItemDTOList);
                    allocateOrderWriteService.delivered(allocateOrderDeliveryRequest);
                } catch (Exception e) {
                    log.error("MnSapIf017V2Service_externalSyncDeliveryOrder error", e);
                }
                //如果是销售单 需要处理预占
                List<ConsignmentOrderLine> freshLines = Lists.newArrayList();
                if (isNeedHandleOccupy) {
                    String deliveryOrderId = SapAndCrmFieldDealUtils.generateIdField(datum.getDeliveryOrderId());
                    ConsignmentOrderLoadListRequest consignmentOrderLoadListRequest = new ConsignmentOrderLoadListRequest();
                    consignmentOrderLoadListRequest.setOuterDeliveryOrderId(deliveryOrderId);
                    consignmentOrderLoadListRequest.setStatus(1);
                    Result<List<ConsignmentOrder>> listResult = consignmentOrderService.loadConsignmentOrderList(consignmentOrderLoadListRequest);
                    log.info("MnSapIf017V2ServiceImpl_freshLoadConsignmentOrder:{}", JSON.toJSONString(listResult));
                    if (listResult != null && CollectionUtils.isNotEmpty(listResult.getResult())) {
                        ConsignmentOrder consignmentOrder = listResult.getResult().get(0);
                        ConsignmentOrderLineLoadListRequest consignmentOrderLineLoadListRequest = new ConsignmentOrderLineLoadListRequest();
                        consignmentOrderLineLoadListRequest.setConsignmentOrderId(consignmentOrder.getId().toString());
                        consignmentOrderLineLoadListRequest.setLimit(MAX_PAGE_SIZE);
                        Result<List<ConsignmentOrderLine>> result = consignmentOrderLineService.loadConsignmentOrderLineList(consignmentOrderLineLoadListRequest);
                        log.info("MnSapIf017V2ServiceImpl_freshLoadConsignmentOrderLines:{}", JSON.toJSONString(result));
                        if (result != null && CollectionUtils.isNotEmpty(result.getResult())) {
                            freshLines = result.getResult();
                        }
                    }
                    handleInventory(datum, consignmentOrderLines, freshLines, orderLineList, targetOrder != null ? targetOrder.getDeliveryStatus() : null, hasDelConsignmentOrder);
                }


                //如果需要校验且校验通过
                if (checkTimestamp) {
                    cache(datum.getDeliveryOrderId(), datum.getExt1());
                }
                //如果重试表有数据需要更改重试表的数据状态;
                try {
                    updateSapRetry(mnSapIf017Request);
                } catch (Throwable e) {
                    log.info("MnSapIf017V2ServiceImpl_updateSapRetry_error", e);
                }
            } catch (Throwable e) {
                log.error("MnSapIf017V2ServiceImpl_inventory_error_request:{}", JSON.toJSONString(mnSapIf017Request));
                log.error("DelDeliveryOrderLockError", e);
                //写入重试表
                saveSapRetry(mnSapIf017Request, e.getMessage());
                return ResponseUtil.fail(mnSapIf017Request, e.getMessage());
            }
        }

        mnSapCommResponse.setData(respData);
        asyncSendMsgToKafka(outSourceOrderIds);
        return mnSapCommResponse;
    }

    /**
     * 新链路
     * @param mnSapIf017Request
     * @return
     */
    private MnSapCommResponse externalSyncDeliveryOrderV2(MnSapIf017Request mnSapIf017Request) {
        MnSapCommResponse mnSapCommResponse = new MnSapCommResponse();

        // Try to get from mogodb if null
        if (mnSapIf017Request == null) {
            mnSapIf017Request = IntegrateUtils.safeGetMessageObject(MnSapIf017Request.class);
        }

        mnSapCommResponse.setMessageId(mnSapIf017Request.getMessageHeader().getMessageId());
        mnSapCommResponse.setInterfacePath(mnSapIf017Request.getMessageHeader().getInterfacePath());
        List<String> outSourceOrderIds=new ArrayList<>();
        List<MnSapCommSDO> respData = new ArrayList<>();
        for (MnSapIf017SDO datum : mnSapIf017Request.getData()) {
            // 包括通过013创建的单子 sap报文里的订单id转换成内部主键id  sap: 1开头 中间补0  总长度10
            datum.setOuterSalesOrderId(CodeUtil.convertTradeOrderId(datum.getOuterSalesOrderId()));
            datum.setOuterStoOrderId(CodeUtil.convertTradeOrderId(datum.getOuterStoOrderId()));
            outSourceOrderIds.add(datum.getOuterSalesOrderId());
            //            String lockKey = DELIVERY_ORDER_LOCK + SapAndCrmFieldDealUtils.generateIdField(datum.getDeliveryOrderId());
            //交货单集成接口和销售单有并发时序问题，使用同一个redis lock来处理
            String outOrderId = SapAndCrmFieldDealUtils.generateIdField(StringUtils.isNotBlank(datum.getSalesOrderId()) ? datum.getSalesOrderId() : datum.getStoOrderId());
            String lockKey = SAP_SYNC + outOrderId;
            try (SaleRedisLock lock = new SaleRedisLock(BcOtsConstants.REDIS_CACHE_CODE(), lockKey,
                2 * 60 * 1000, 10 * 60 * 1000)) {
                if (!lock.lock()) {
                    //写入重试表
                    saveSapRetry(mnSapIf017Request, "获取分布式锁错误");
                    return ResponseUtil.fail(mnSapIf017Request, "获取分布式锁错误");
                }
                log.info("MnSapIf017V2ServiceImpl_getLock");
                if (checkTimestamp) {
                    String check = ResponseUtil.check(datum.getExt1());
                    if (StringUtils.isNotBlank(check)) {
                        //                    saveSapRetry(mnSapIf017Request,check);
                        MnSapCommSDO mnSapCommSDO = new MnSapCommSDO();
                        mnSapCommSDO.setStatus("E");
                        mnSapCommSDO.setMessage(check);
                        mnSapCommSDO.setHeaderKey(datum.getHeaderKey());
                        List<MnSapCommDetail> commDetails = new ArrayList<>();
                        MnSapCommDetail mnSapCommDetail = new MnSapCommDetail();
                        mnSapCommDetail.setStatus("E");
                        mnSapCommDetail.setMessage(check);
                        //                mnSapCommDetail.setItemKey(item.getItem_key());
                        commDetails.add(mnSapCommDetail);
                        mnSapCommSDO.setItem(commDetails);
                        respData.add(mnSapCommSDO);
                        mnSapCommResponse.setData(respData);
                        return mnSapCommResponse;
                    }
                    boolean checkModifierTime = checkModifierTime(datum);
                    if (!checkModifierTime) {
                        //时间戳校验不通过需要抛错 放入重试表
                        saveSapRetry(mnSapIf017Request, "当前修改时间早于上一次 不允许更新");
                        MnSapCommSDO mnSapCommSDO = new MnSapCommSDO();
                        mnSapCommSDO.setStatus("E");
                        mnSapCommSDO.setMessage("当前修改时间早于上一次 不允许更新");
                        mnSapCommSDO.setHeaderKey(datum.getHeaderKey());
                        List<MnSapCommDetail> commDetails = new ArrayList<>();
                        MnSapCommDetail mnSapCommDetail = new MnSapCommDetail();
                        mnSapCommDetail.setStatus("E");
                        mnSapCommDetail.setMessage("当前修改时间早于上一次 不允许更新");
                        //                mnSapCommDetail.setItemKey(item.getItem_key());
                        commDetails.add(mnSapCommDetail);
                        mnSapCommSDO.setItem(commDetails);
                        respData.add(mnSapCommSDO);
                        mnSapCommResponse.setData(respData);
                        return mnSapCommResponse;
                    } else {
                        //校验通过就要放入时间戳
                        //                    cache(datum.getDeliveryOrderId(),datum.getExt());
                    }

                }

                //销售单是否需要预占库存
                boolean occupyFlg = false;
                String salesOrderId = null;
                String bizOrderId = null;

                ConsignmentOrderWriteCreateRequest request = new ConsignmentOrderWriteCreateRequest();
                request.setOuterDeliveryOrderId(SapAndCrmFieldDealUtils.generateIdField(datum.getDeliveryOrderId()));
                request.setOuterSalesOrderId(SapAndCrmFieldDealUtils.generateIdField(datum.getSalesOrderId()));
                request.setSalesOrderId(SapAndCrmFieldDealUtils.generateIdField(datum.getOuterSalesOrderId()));
                request.setOuterStoOrderId(SapAndCrmFieldDealUtils.generateIdField(datum.getStoOrderId()));
                request.setCreator(SapAndCrmFieldDealUtils.generateIdField(datum.getCreator()));
                request.setModifier(SapAndCrmFieldDealUtils.generateIdField(datum.getModifier()));
                request.setSalesOrgId(datum.getSalesOrgId());
                request.setStoOrderId(SapAndCrmFieldDealUtils.generateIdField(datum.getOuterStoOrderId()));
                request.setCreator(datum.getCreator());
                //request.setCreatDate(SapAndCrmFieldDealUtils.toDate(datum.getCreatDate()));
                Date now = new Date();
                request.setCreatDate(now);
                request.setModifier(datum.getModifier());
                //request.setModifidDate(SapAndCrmFieldDealUtils.toDate(datum.getModifidDate()));
                request.setModifidDate(now);
                request.setDeliveryDate(SapAndCrmFieldDealUtils.toDate(datum.getDeliveryDate()));
                request.setFeatures(datum.getFeatures());

                //013接口会同步特殊的销售单，判断ext=ZORO且销售组织是1171的交货单，修改为销售订单类型的交货单
                if ((StringUtils.isNotBlank(datum.getExt()) && saleOrderExtList.contains(datum.getExt())) && (
                    StringUtils.isNotBlank(datum.getSalesOrgId()) && SPEC_ORG.equalsIgnoreCase(datum.getSalesOrgId())
                )) {
                    request.setOuterSalesOrderId(SapAndCrmFieldDealUtils.generateIdField(datum.getStoOrderId()));
                }

                //开始处理明细
                MnSapCommSDO mnSapCommSDO = new MnSapCommSDO();
                mnSapCommSDO.setStatus("S");
                mnSapCommSDO.setMessage("成功");
                mnSapCommSDO.setHeaderKey(datum.getHeaderKey());
                List<MnSapCommDetail> details = new ArrayList<>();
                List<AllocateOrderDeliveryScItemDTO> scItemDTOList = Lists.newArrayList();
                List<ConsignmentOrderLineRequest> collect = new ArrayList<>();
                for (MnSapIf017Detail item : datum.getItems()) {
                    ConsignmentOrderLineRequest lineRequest = new ConsignmentOrderLineRequest();
                    lineRequest.setOuterOrderLineId(SapAndCrmFieldDealUtils.generateIdField(item.getOrderLineId()));
                    lineRequest.setOuterSoLineId(SapAndCrmFieldDealUtils.generateIdField(item.getSoLineId()));
                    lineRequest.setSoLineId(SapAndCrmFieldDealUtils.generateIdField(item.getOuterSoLineId()));
                    lineRequest.setOuterStoLineId(SapAndCrmFieldDealUtils.generateIdField(item.getStoLineId()));
                    lineRequest.setStoLineId(SapAndCrmFieldDealUtils.generateIdField(item.getOuterStoLineId()));
                    if ((StringUtils.isNotBlank(datum.getExt()) && saleOrderExtList.contains(datum.getExt())) && (
                        StringUtils.isNotBlank(datum.getSalesOrgId()) && SPEC_ORG.equalsIgnoreCase(datum.getSalesOrgId())
                    )) {
                        lineRequest.setOuterSoLineId(SapAndCrmFieldDealUtils.generateIdField(item.getStoLineId()));
                    }
                    String scItemId = null;
                    try {
                        SearchScItemByDBWhenDegradedRequest searchScItemByDBWhenDegradedRequest = new SearchScItemByDBWhenDegradedRequest();
                        Map<Object, Object> objectObjectMap = Maps.newLinkedHashMap();
                        objectObjectMap.put("outerId", SapAndCrmFieldDealUtils.generateScItemIdField(item.getScItemId()));
                        //需要查出货品被禁用的 1启用 -1禁用
                        objectObjectMap.put("statusList", Lists.newArrayList(1, -1));
                        searchScItemByDBWhenDegradedRequest.setSearchReqDTO(objectObjectMap);
                        Result<List<ScItemSDO>> listResult = baseDataService.searchScItemByDBWhenDegraded(searchScItemByDBWhenDegradedRequest);
                        if (Objects.nonNull(listResult) && CollectionUtils.isNotEmpty(listResult.getResult())) {
                            scItemId = listResult.getResult().get(0).getScItemId();
                            ;
                        }
                        //2022.05.19 因为定时器里用callAPI报错了 会引起未知的问题 所以callAPI放弃使用
                    } catch (Throwable e) {
                        log.error("MnSapIf017ServiceImpl_scItemConvertError", e);
                    }
                    if (StringUtils.isBlank(scItemId)) {
                        log.error("MnSapIf017ServiceImpl_scItemConvertError:{}", item.getScItemId());
                        mnSapCommSDO.setStatus("E");
                        mnSapCommSDO.setMessage(item.getScItemId() + " 货品编码转换失败");
                        mnSapCommSDO.setHeaderKey(datum.getHeaderKey());
                        List<MnSapCommDetail> commDetails = new ArrayList<>();
                        MnSapCommDetail mnSapCommDetail = new MnSapCommDetail();
                        mnSapCommDetail.setStatus("E");
                        mnSapCommDetail.setMessage(item.getScItemId() + " 货品编码转换失败");
                        mnSapCommDetail.setItemKey(item.getItem_key());
                        commDetails.add(mnSapCommDetail);
                        mnSapCommSDO.setItem(commDetails);
                        respData.add(mnSapCommSDO);
                        mnSapCommResponse.setData(respData);
                        saveSapRetry(mnSapIf017Request, item.getScItemId() + " 货品编码转换失败");
                        return mnSapCommResponse;
                    }

                    //                JSONObject scItemJson = scItemJsonArray.getJSONObject(0);
                    lineRequest.setScItemId(scItemId);
                    lineRequest.setQty(item.getQty());
                    lineRequest.setPodStatus(item.getPodStatus());
                    lineRequest.setPodQty(item.getPodQty());
                    lineRequest.setFactoryCode(item.getFactoryCode());
                    lineRequest.setInventoryCode(item.getInventoryCode());
                    lineRequest.setSaleUnit(item.getSaleUnit());
                    lineRequest.setBasicQuantity(item.getBasicQuantity());
                    collect.add(lineRequest);

                    AllocateOrderDeliveryScItemDTO scItemDTO = new AllocateOrderDeliveryScItemDTO();
                    scItemDTO.setScItemCode(subStringScItmCode(item.getScItemId()));
                    scItemDTO.setDeliveryQuantity(item.getQty());
                    //文档 和数据库 是反着来的 此处指报文里的stoLineId为调拨单的外部行号 去掉前缀0
                    scItemDTO.setOutAllocateOrderLineId(InfoUtil.deleteZeroPrefix(item.getStoLineId()));
                    //                scItemDTO.setOutAllocateOrderLineId(item.getOuterStoLineId());
                    scItemDTOList.add(scItemDTO);

                    MnSapCommDetail mnSapCommDetail = new MnSapCommDetail();
                    mnSapCommDetail.setStatus("S");
                    mnSapCommDetail.setMessage("成功");
                    mnSapCommDetail.setItemKey(item.getItem_key());
                    details.add(mnSapCommDetail);
                    mnSapCommSDO.setItem(details);
                }
                respData.add(mnSapCommSDO);

                request.setConsignmentOrderLineRequest(collect);
                boolean salesOrderFlag = false;
                boolean allocateOrderFlag = false;
                //2022.05.18 如果查询不到调拨单/销售单 那么就需要重试
                if (StringUtils.isNotBlank(request.getOuterSalesOrderId())) {
                    LoadOrderListRequest loadOrderListRequest = new LoadOrderListRequest();
                    //此处不能去0 因为销售单里的外部单号存了0
                    loadOrderListRequest.setOuterOrderId(request.getOuterSalesOrderId());
                    log.info("017 loadOrderList a req={}", JSON.toJSONString(loadOrderListRequest));
                    Result<List<Order>> listResult = orderService.loadOrderList(loadOrderListRequest);
                    log.info("017 loadOrderList a res={}", JSON.toJSONString(listResult));
                    if (Objects.isNull(listResult) || CollectionUtils.isEmpty(listResult.getResult())) {
                        // 不去掉0再查一次
                        loadOrderListRequest.setOuterOrderId(datum.getSalesOrderId());
                        log.info("017 loadOrderList b req={}", JSON.toJSONString(loadOrderListRequest));
                        listResult = orderService.loadOrderList(loadOrderListRequest);
                        log.info("017 loadOrderList b res={}", JSON.toJSONString(listResult));
                        if (Objects.isNull(listResult) || CollectionUtils.isEmpty(listResult.getResult())) {
                            saveSapRetry(mnSapIf017Request, "交货单查询不到销售单");
                            return ResponseUtil.fail(mnSapIf017Request, "交货单查询不到销售单");
                        }

                    }
                    salesOrderFlag = true;
                    //是销售单需要进行库存预占逻辑
                    //occupyFlg = true;
                    Order order = listResult.getResult().get(0);
                    //salesOrderId = String.valueOf(order.getId());
                    bizOrderId = order.getOrderBizId();

                } else if (StringUtils.isNotBlank(request.getOuterStoOrderId())) {
                    // stoOrderId可能是总部销售调拨单/纯粹的调拨单/F-B的订单
                    AllocateOrderLoadListRequest allocateOrderLoadListRequest = new AllocateOrderLoadListRequest();
                    allocateOrderLoadListRequest.setOutAllocateOrderId(request.getOuterStoOrderId());
                    log.info("017 loadAllocateOrderList req={}", JSON.toJSONString(allocateOrderLoadListRequest));
                    Result<List<AllocateOrder>> loadAllocateOrderList = allocateOrderService.loadAllocateOrderList(allocateOrderLoadListRequest);
                    log.info("017 loadAllocateOrderList res={}", JSON.toJSONString(loadAllocateOrderList));
                    if (loadAllocateOrderList == null || CollectionUtils.isEmpty(loadAllocateOrderList.getResult())) {
                        // 查不到调拨单，再查销售单
                        LoadOrderListRequest loadOrderListRequest = new LoadOrderListRequest();
                        loadOrderListRequest.setOuterOrderId(request.getOuterStoOrderId());
                        log.info("017 loadOrderList c req={}", JSON.toJSONString(loadOrderListRequest));
                        Result<List<Order>> listResult = orderService.loadOrderList(loadOrderListRequest);
                        log.info("017 loadOrderList c res={}", JSON.toJSONString(listResult));
                        if (Objects.isNull(listResult) || CollectionUtils.isEmpty(listResult.getResult())) {
                            // 不去掉0再查一次
                            loadOrderListRequest.setOuterOrderId(datum.getStoOrderId());
                            log.info("017 loadOrderList d req={}", JSON.toJSONString(loadOrderListRequest));
                            listResult = orderService.loadOrderList(loadOrderListRequest);
                            log.info("017 loadOrderList d res={}", JSON.toJSONString(listResult));
                            if (Objects.isNull(listResult) || CollectionUtils.isEmpty(listResult.getResult())) {
                                saveSapRetry(mnSapIf017Request, "交货单查询不到销售单和调拨单");
                                return ResponseUtil.fail(mnSapIf017Request, "交货单查询不到销售单和调拨单");
                            }
                        }
                        // 修正字段的值，sto字段给so字段赋值
                        request.setOuterSalesOrderId(request.getOuterStoOrderId());
                        request.setOuterStoOrderId(null);
                        request.setSalesOrderId(request.getStoOrderId());
                        request.setStoOrderId(null);
                        for (ConsignmentOrderLineRequest line : request.getConsignmentOrderLineRequest()) {
                            line.setOuterSoLineId(line.getOuterStoLineId());
                            line.setOuterStoLineId(null);
                            line.setSoLineId(line.getStoLineId());
                            line.setStoLineId(null);
                        }
                        bizOrderId = listResult.getResult().get(0).getOrderBizId();
                        salesOrderFlag = true;

                        //saveSapRetry(mnSapIf017Request, "交货单查询不到调拨单");
                        //return ResponseUtil.fail(mnSapIf017Request, "交货单查询不到调拨单");
                    } else {
                        bizOrderId = loadAllocateOrderList.getResult().get(0).getCode();
                        allocateOrderFlag = true;
                        //AllocateOrder allocateOrder = loadAllocateOrderList.getResult().get(0);
                        //if (skip017(allocateOrder)) {
                        //    log.info("MnSapIf017V2Service skip allocateOrderId={},fulfillmentTypeCode={}",
                        //        allocateOrder.getId(), allocateOrder.getFulfillmentTypeCode());
                        //    return ResponseUtil.success(mnSapIf017Request);
                        //}
                    }
                }

                try {
                    boolean bcLinkDone = toBcLink(request, datum.getDeliveryOrderId());
                    if (!bcLinkDone) {
                        request.setOuterDeliveryOrderId(SapAndCrmFieldDealUtils.generateIdField(request.getOuterDeliveryOrderId()));
                        ConsignmentOrderQueryRequest queryRequest = new ConsignmentOrderQueryRequest();
                        queryRequest.setOuterDeliveryOrderId(request.getOuterDeliveryOrderId());
                        log.info("MnSapIf017V2ServiceImpl_query_consignmentOrder request={}", JSON.toJSONString(queryRequest));
                        Result<ConsignmentOrderSDO> queryResult = consignmentOrderQueryService.querySingle(queryRequest);
                        log.info("MnSapIf017V2ServiceImpl_query_consignmentOrder result={}", JSON.toJSONString(queryResult));
                        if (queryResult != null && queryResult.getResult() != null) {
                            log.info("MnSapIf017V2ServiceImpl was created outerDeliveryOrderId={}", request.getOuterDeliveryOrderId());
                        } else {
                            log.info("MnSapIf017V2ServiceImpl_create_consignmentOrder request={}", JSON.toJSONString(request));
                            Result<ConsignmentOrderCreateResponse> createResult = consignmentOrderWriteService.create(request);
                            log.info("MnSapIf017V2ServiceImpl_create_consignmentOrder result={}", JSON.toJSONString(createResult));
                        }
                    }

                } catch (Throwable e) {
                    log.error("MnSapIf017V2ServiceImpl_create_error", e);
                    saveSapRetry(mnSapIf017Request, "交货单更新异常");
                    return ResponseUtil.fail(mnSapIf017Request, "交货单更新异常");
                }

                // TBD 这里的异常处理和返回值处理需要优化，除非确定是弱依赖，
                try {
                    AllocateOrderDeliveryRequest allocateOrderDeliveryRequest = new AllocateOrderDeliveryRequest();
                    allocateOrderDeliveryRequest.setCode(datum.getOuterStoOrderId());
                    if (StringUtils.isNotBlank(datum.getStoOrderId())) {
                        allocateOrderDeliveryRequest.setOutAllocateOrderId(datum.getStoOrderId());
                    }
                    allocateOrderDeliveryRequest.setDeliveryDate(datum.getDeliveryDate());
                    //实际用这个作为交货日期
                    allocateOrderDeliveryRequest.setCreateDate(datum.getCreatDate());
                    //更改调拨单的交货数量
                    //allocateOrderDeliveryRequest.setDeliveryScItemDTOList(scItemDTOList);
                    log.info("MnSapIf017V2ServiceImpl#delivered request={}", JSON.toJSONString(allocateOrderDeliveryRequest));
                    Result<AllocateOrderDeliveryResponse> result = allocateOrderWriteService.delivered(allocateOrderDeliveryRequest);
                    log.info("MnSapIf017V2ServiceImpl#delivered result={}", JSON.toJSONString(result));
                } catch (Exception e) {
                    log.error("MnSapIf017V2Service_externalSyncDeliveryOrder error", e);
                }


                //如果需要校验且校验通过
                if (checkTimestamp) {
                    cache(datum.getDeliveryOrderId(), datum.getExt1());
                }
                //如果重试表有数据需要更改重试表的数据状态;
                try {
                    updateSapRetry(mnSapIf017Request);
                } catch (Throwable e) {
                    log.info("MnSapIf017V2ServiceImpl_updateSapRetry_error", e);
                }
            } catch (Throwable e) {
                log.error("MnSapIf017V2ServiceImpl_inventory_error_request:{}", JSON.toJSONString(mnSapIf017Request));
                log.error("DelDeliveryOrderLockError", e);
                //写入重试表
                saveSapRetry(mnSapIf017Request, e.getMessage());
                return ResponseUtil.fail(mnSapIf017Request, e.getMessage());
            }
        }

        mnSapCommResponse.setData(respData);
        asyncSendMsgToKafka(outSourceOrderIds);
        return mnSapCommResponse;
    }

    /**
     * 在bc-link里面处理，这样执行记录里面就有017的记录
     * @param request
     * @return
     */
    private boolean toBcLink(ConsignmentOrderWriteCreateRequest request, String outDeliveryOrderId) {
        try {
            request.setOuterDeliveryOrderId(outDeliveryOrderId);
            Map<String, String> header = HttpTokenUtil.generateHttpHeader();
            String urlPrefix = OtsApplicationAdapterSdkConstants.urlPrefix();
            String url = urlPrefix + "api/mn_bc_link/sapDeliveryOrder017";
            log.info("MnSapIf017V2ServiceImpl boBcLink request={}", JSON.toJSONString(request));
            ResponseEntity<com.alibaba.cirtus.ots.application.adapter.ability.model.Result> post = httpUtils.post(url,
                header, request, com.alibaba.cirtus.ots.application.adapter.ability.model.Result.class);
            com.alibaba.cirtus.ots.application.adapter.ability.model.Result result = post.getBody();
            log.info("MnSapIf017V2ServiceImpl boBcLink result:{}", JSON.toJSONString(result));
            return result != null && result.isSuccess() && result.getResult() != null;
        } catch (Exception e) {
            log.error("MnSapIf017V2ServiceImpl boBcLink error", e);
        }
        return false;
    }

    private boolean skip017(AllocateOrder allocateOrder) {
        // todo 如果交货单对应的业务单据是调拨单，而且调拨单的履约方式为（大仓发大仓收，大仓发外仓收，外仓发大仓收），则忽略017报文。
        List<String> skipTypes = Lists.newArrayList("100", "110", "120");
        return skipTypes.contains(allocateOrder.getFulfillmentTypeCode());
    }



    /**
     * 判断物料凭证是否在试点范围内的
     * @param sdo
     * @return
     */
    public boolean isInPilotScope(MnSapIf017SDO sdo){
        List<MnSapIf017Detail> detailList = Optional.ofNullable(sdo).map(MnSapIf017SDO::getItems).orElse(Lists.newArrayList());
        return Nullable.stream(detailList).findFirst()
            .map(detail -> isInPilotScope(detail.getFactoryCode(),detail.getInventoryCode()))
            .orElse(Boolean.FALSE);
    }
    /**
     * 根据工厂编码 + 库存地点
     * @param factoryCode
     * @param warehouseCode
     * @return
     */
    public boolean isInPilotScope(String factoryCode,String warehouseCode){
        //        com.alibaba.cloud.retail.link.sdk.dto.Result<Boolean> result = pilotLogicWarehouseService.checkPilotByFactoryCodeAndInventoryCode(factoryCode, warehouseCode);
        CheckPilotByFactoryCodeAndInventoryCodeRequest request = new CheckPilotByFactoryCodeAndInventoryCodeRequest();
        if (StringUtils.isNotBlank(factoryCode)){
            request.setFactoryCode(factoryCode);
        }
        if (StringUtils.isNotBlank(warehouseCode)){
            request.setInventoryCode(warehouseCode);
        }
        Result<Boolean> result = otsApplicationAdapterSdkService.checkPilotByFactoryCodeAndInventoryCode(request);
        return Optional.ofNullable(result).map(Result::getResult).orElse(Boolean.FALSE);
    }

    /**
     * 发送mq消息，异步发送kafka消息通知应用端
     */
    private void asyncSendMsgToKafka(List<String> outSourceOrderIds) {
        if (CollectionUtils.isEmpty(outSourceOrderIds)) {
            return;
        }

        QueryByOuterOrderIdsRequest pageQueryRequest = new QueryByOuterOrderIdsRequest();
        pageQueryRequest.setOuterOrderIds(outSourceOrderIds);
        pageQueryRequest.setLimit(outSourceOrderIds.size());
        Result<List<Order>> listResult = orderService.queryByOuterOrderIds(pageQueryRequest);
        if (Objects.isNull(listResult) || CollectionUtils.isEmpty(listResult.getResult())) {
            return;
        }

        String fromSys = "";
        String businessUnitCode = "";
        List<PushOrderInfoToMnSideRequestOrderInfo> pushOrderInfos = new ArrayList<>();
        for (Order order : listResult.getResult()) {
            if (!JsonUtil.checkOrderCenterTag(order.getFeatures())) {
                // 非订单中心订单不发kafka消息
                continue;
            }
            if (StringUtils.isBlank(fromSys) && StringUtils.isNotBlank(order.getFromSys())) {
                fromSys = order.getFromSys();
            }
            if (StringUtils.isBlank(businessUnitCode) && StringUtils.isNotBlank(order.getBisUnitOutCode())) {
                fromSys = order.getBisUnitOutCode();
            }

            PushOrderInfoToMnSideRequestOrderInfo pushOrderInfo = new PushOrderInfoToMnSideRequestOrderInfo();
            pushOrderInfo.setSalesOrderNo(order.getOrderBizId());
            pushOrderInfo.setOrderStatus(SalesOrderPushStatusEnum.SUCCESS_UPDATE.getOrderStatusCode());
            pushOrderInfos.add(pushOrderInfo);
        }
        if (CollectionUtils.isEmpty(pushOrderInfos)) {
            return;
        }

        CommonAsyncMessageResponse commonAsyncMessageResponse = new CommonAsyncMessageResponse();
        commonAsyncMessageResponse.setEventCode(AsyncMessageEventEnum.SALES_ORDER_UPDATE.getValue());
        commonAsyncMessageResponse.setEventName(AsyncMessageEventEnum.SALES_ORDER_UPDATE.getLabel());
        commonAsyncMessageResponse.setEventTime(String.valueOf(new Date().getTime()));
        commonAsyncMessageResponse.setFromSys(fromSys);
        commonAsyncMessageResponse.setBusinessUnitCode(businessUnitCode);
        commonAsyncMessageResponse.setData(pushOrderInfos);

        messageService.sendMessage("ORDER_STATUSCHANGE_PUSH_MESSAGE", "CR_SALEORDER_V2", "SaleOrderPushMn",
                JSONObject.toJSONString(commonAsyncMessageResponse));
        log.info("MnSapIf017V2Service#asynSendMsgToKafka commonAsyncMessageResponse: {}", commonAsyncMessageResponse);
    }

    //更新重试记录
    private void updateSapRetry(MnSapIf017Request request) {
        if (request == null || request.getMessageHeader() == null || StringUtils.isBlank(request.getMessageHeader().getMessageId())) {
            return;
        }
        String messageId = request.getMessageHeader().getMessageId();
        SapRetryLoadListRequest sapRetryLoadListRequest = new SapRetryLoadListRequest();
        sapRetryLoadListRequest.setMessageId(messageId);
        sapRetryLoadListRequest.setStatus(RetryStatus.FAIL.getValue());
        Result<List<SapRetry>> listResult = sapRetryService.loadList(sapRetryLoadListRequest);
        if (listResult == null || CollectionUtils.isEmpty(listResult.getResult())) {
            return;
        }
        for (SapRetry sapRetry : listResult.getResult()) {
            sapRetry.setRetryTimes(sapRetry.getRetryTimes() + 1);
            sapRetry.setStatus(RetryStatus.SUCCESS.getValue());
            log.info("MnSapIf017V2ServiceImpl_updateSapRetry:{}", JSON.toJSONString(sapRetry));
            sapRetryService.update(sapRetry);
        }

    }

    /**
     * 截取scItemCode 固定长度为12
     *
     * @param str
     * @return
     */
    public static String subStringScItmCode(String str) {
        if (StringUtils.isBlank(str)) {
            return null;
        }
        if (str.length() > 12) {
            return str.substring(str.length() - 12);
        }
        return str;
    }

    public void saveSapRetry(MnSapIf017Request request, String message) {
        try {
            if (request == null || StringUtils.isBlank(message)) {
                return;
            }
            MnSapIf017SDO sdo = request.getData().get(0);
            SapRetrySaveRequest sapRetrySaveRequest = new SapRetrySaveRequest();
            String requestJson = JSON.toJSONString(request);
            sapRetrySaveRequest.setParam(requestJson);
            sapRetrySaveRequest.setMsg(message);
            sapRetrySaveRequest.setMessageId(request.getMessageHeader().getMessageId());
            //请求时间戳
            sapRetrySaveRequest.setRequestTime(sdo.getExt1());
            sapRetrySaveRequest.setApiCode(SapApiCode.SAP017.getValue());
            sapRetrySaveRequest.setOutKey(sdo.getDeliveryOrderId());
            sapRetrySaveRequest.setStatus(RetryStatus.FAIL.getValue());
            //2022.09.01新加查询字段ext
            sapRetrySaveRequest.setExt(StringUtils.isNotBlank(sdo.getSalesOrderId()) ? sdo.getSalesOrderId() : sdo.getStoOrderId());
            sapRetryWriteService.save(sapRetrySaveRequest);
        } catch (Throwable e) {
            log.error("sapRetrySaveError", e);
        }
    }

    /**
     * 检查时间戳
     **/
    boolean checkModifierTime(MnSapIf017SDO datum) {
        String modifierTime = epochCacheService.get(BcOtsConstants.REDIS_CACHE_CODE(),
                DELIVERY_ORDER_CACHE_KEY + datum.getDeliveryOrderId());
        String ext = datum.getExt1();
        if (StringUtils.isNotBlank(modifierTime)) {
            String[] modifierTimeArray = modifierTime.split("\\.");
            String[] extArray = ext.split("\\.");
            if (Long.parseLong(modifierTimeArray[0]) > Long.parseLong(extArray[0])) {
                return false;
            } else if (Long.valueOf(modifierTimeArray[0]).longValue() == Long.valueOf(extArray[0]).longValue()) {
                if (Long.parseLong(modifierTimeArray[1]) >= Integer.valueOf(extArray[1]).longValue()) {
                    return false;
                }
            }
        }
        return true;
    }

    void cache(String key, String time) {
        if (StringUtils.isAnyBlank(key, time)) {
            return;
        }
        epochCacheService.put(BcOtsConstants.REDIS_CACHE_CODE(),
                DELIVERY_ORDER_CACHE_KEY + key, time,
                SAP_TIMESTAMP_CACHE_EXPIRE,
                TimeUnit.SECONDS);
    }


    private void handleInventory(MnSapIf017SDO sdo, List<ConsignmentOrderLine> oldLines,
                                 List<ConsignmentOrderLine> freshLines, List<OrderLine> orderLines,
                                 Integer deliveryStatus, boolean hasDelConsignmentOrder) {
        Pair<OccupyRequest, OccupyReleaseRequest> diff = getDiff(sdo, oldLines, freshLines, orderLines, hasDelConsignmentOrder);
        log.info("MnSapIf017V2ServiceImpl_handleInventory_getDiff_result:{}", JSON.toJSONString(diff));
        if (diff == null) {
            return;
        }

        OccupyRequest left = diff.getLeft();
        //如果是004请求了,部分交货/已完成 就不预占
        if (left != null && CollectionUtils.isNotEmpty(left.getInvOperateLineList())) {
            if (!Objects.equals(deliveryStatus, OrderStatus.PARTIAL_DELIVER.getCode()) &&
                    !Objects.equals(deliveryStatus, OrderStatus.COMPLETED.getCode())) {
                log.info("MnSapIf017V2ServiceImpl_occupy_request:{}", JSON.toJSONString(left));
                Result<OccupyResponse> occupy = crUnifiedInventoryService.occupy(left);
                log.info("MnSapIf017V2ServiceImpl_occupy_result:{}", JSON.toJSONString(occupy));
                if (occupy == null || !occupy.isSuccess()) {
                    throw new FacadeException("OTS-03-005-00-15-170");
                }
            }
        }
        OccupyReleaseRequest right = diff.getRight();
        if (right != null && CollectionUtils.isNotEmpty(right.getInvOperateLineList())) {
            log.info("MnSapIf017V2ServiceImpl_occupyRelease_request:{}", JSON.toJSONString(right));
            Result<OccupyReleaseResponse> occupyReleaseResponseResult = crUnifiedInventoryService.occupyRelease(right);
            log.info("MnSapIf017V2ServiceImpl_occupyRelease_result:{}", JSON.toJSONString(occupyReleaseResponseResult));
            if (occupyReleaseResponseResult == null || !occupyReleaseResponseResult.isSuccess()) {
                throw new FacadeException("OTS-03-005-00-15-169");
            }
        }
    }

    /**
     * 销售单 根据交货单来更新平台库存预占逻辑
     **/
//    public Boolean salesOrderInvOccupy(MnSapIf017SDO datum,List<ConsignmentOrderLine> consignmentOrderLines,List<OrderLine> orderLineList) {
//            //017销售单释放库存处理逻辑
//            //历史交货单不为空，根据历史交货单释放库存
//            String modifierTime = epochCacheService.get(BcOtsConstants.REDIS_CACHE_CODE(),
//                DELIVERY_ORDER_CACHE_KEY + datum.getDeliveryOrderId());
//            boolean isSaleOrder = isSaleOrder(datum);
//            if (!isSaleOrder){
//                return false;
//            }
//        if (CollectionUtils.isNotEmpty(consignmentOrderLines)) {
//                OccupyReleaseRequest occupyReleaseRequest = new OccupyReleaseRequest();
////                ConsignmentOrder consignmentOrder = loadConsignmentOrderList.get(0);
//
//                String outDeliveryOrderNo = SapAndCrmFieldDealUtils.generateIdField(datum.getDeliveryOrderId());
//                //判断一下
//                String outerSalesOrderId = StringUtils.isNotBlank(datum.getSalesOrderId())?
//                        datum.getSalesOrderId() : datum.getStoOrderId();
//                //如果销售单存在查销售单
//                if (StringUtils.isBlank(outerSalesOrderId)){
//                    throw new FacadeException("OTS-03-005-00-15-162");
//                }
//                LoadOrderListRequest loadOrderListRequest = new LoadOrderListRequest();
//                loadOrderListRequest.setOuterOrderId(outerSalesOrderId);
//                Result<List<Order>> orderListResult = orderService.loadOrderList(loadOrderListRequest);
//                //如果是销售单
//                if (orderListResult != null && CollectionUtils.isNotEmpty(orderListResult.getResult())){
//                    List<Order> orderList = orderListResult.getResult();
//                    Order order = orderList.get(0);
//                    //逻辑仓库id
//                    String wareHouseCode = order.getWareHouseCode();
//                    //获取仓库档案id
//                    //获取交货单明细
////                    ConsignmentOrderLineLoadListRequest consignmentOrderLineLoadListRequest = new ConsignmentOrderLineLoadListRequest();
////                    consignmentOrderLineLoadListRequest.setConsignmentOrderId(consignmentOrder.getId().toString());
////                    Result<List<ConsignmentOrderLine>> listResult = consignmentOrderLineService.loadConsignmentOrderLineList(consignmentOrderLineLoadListRequest);
////                    if (listResult != null && CollectionUtils.isNotEmpty(listResult.getResult())){
//                    if (CollectionUtils.isNotEmpty(consignmentOrderLines)){
//                        //获取 outSOLineId - quantity 理论上行不会重复
//                        Map<String, List<ConsignmentOrderLine>> lineMap = consignmentOrderLines.stream().collect(Collectors.groupingBy(ConsignmentOrderLine::getOuterSoLineId));
//                        List<InvOperateLine> invOperateLineList = Lists.newArrayList();
//                        lineMap.forEach((k,v)->{
//                            //库存释放Request
//                            InvOperateLine invOperateLine = new InvOperateLine();
//
//                            if (CollectionUtils.isEmpty(v)){
//                                //error
//                                throw new FacadeException("OTS-03-005-00-15-163");
//                            }
//                            String scItemId = v.get(0).getScItemId();
//                            if (StringUtils.isBlank(scItemId)){
//                                //error
//                                throw new FacadeException("OTS-03-005-00-15-164");
//                            }
//                            invOperateLine.setGoodsId(scItemId);
//                            invOperateLine.setDeleted(true);
//                            invOperateLine.setType("2");
//                            invOperateLine.setOutOrderId(outDeliveryOrderNo);
//                            //用缓存中上次的时间戳
//                            invOperateLine.setOutSubOrderId(modifierTime);
//                            invOperateLine.setWarehouseAreaId(wareHouseCode);
//                            //
//                            WmsSDO wmsSDO = InfoUtil.getWmsSDO(wareHouseCode);
//                            if (StringUtils.isBlank(wmsSDO.getWarehouseId())){
//                                //error
//                                throw new FacadeException("OTS-03-005-00-15-165");
//                            }
//                            invOperateLine.setWarehouseId(wmsSDO.getWarehouseId());
//                            invOperateLine.setReferenceOrderId(order.getId().toString());
//                            OrderLineLoadListRequest orderLineLoadListRequest = new OrderLineLoadListRequest();
//                            orderLineLoadListRequest.setMainOrderId(order.getId().toString());
//                            orderLineLoadListRequest.setOuterOrderLineId(k);
//                            Result<List<OrderLine>> lineResult = orderLineService.loadOrderLineList(orderLineLoadListRequest);
//                            if (lineResult == null || CollectionUtils.isEmpty(lineResult.getResult())){
//                                //error
//                                throw new FacadeException("OTS-03-005-00-15-166");
//                            }
//                            OrderLine orderLine = lineResult.getResult().get(0);
//                            invOperateLine.setReferenceSubOrderId(orderLine.getId().toString());
//                            Long quantity = v.stream().mapToLong(x -> {
//                                if (StringUtils.isBlank(x.getQty())) {
//                                    return 0L;
//                                }
//                                BigDecimal bigDecimal = new BigDecimal(x.getQty().trim());
//                                return bigDecimal.movePointRight(3).longValue();
//                            }).sum();
//                            if (quantity <= 0 ){
//                                //error
//                                throw new FacadeException("OTS-03-005-00-15-167");
//                            }
//                            invOperateLine.setQuantity(quantity.toString());
//                            invOperateLineList.add(invOperateLine);
//                        });
//                        if (CollectionUtils.isEmpty(invOperateLineList)){
//                            //error
//                            throw new FacadeException("OTS-03-005-00-15-168");
//                        }
//                        occupyReleaseRequest.setInvOperateLineList(invOperateLineList);
//                        LOG.info("MnSapIf017ServiceImpl_salesOrderInvOccupy,request:{},occupyReleaseRequest:{}",JSON.toJSONString(outDeliveryOrderNo),JSON.toJSONString(occupyReleaseRequest));
//                        Result<OccupyReleaseResponse> occupyReleaseResponseResult = otsUnifiedInventoryService.occupyRelease(occupyReleaseRequest);
//                        if (occupyReleaseResponseResult == null || !occupyReleaseResponseResult.isSuccess()){
//                            //error
//                            throw new FacadeException("OTS-03-005-00-15-169");
//                        }
//                    }
//                }
//            }
//            //没有历史交货单 根据销售子单封装释放库存参数
//            if (CollectionUtils.isNotEmpty(orderLineList)) {
//                OccupyReleaseRequest occupyReleaseRequest = new OccupyReleaseRequest();
//                List<InvOperateLine> invOperateLineList = Lists.newArrayList();
//
//                for (OrderLine orderLine : orderLineList) {
//                    //过滤关闭的单子
//                    if (ReasonForRejectionEnum.Z1.getCode().equals(orderLine.getRefuseReasonCode())) {
//                        continue;
//                    }
//                    InvOperateLine invOperateLine = new InvOperateLine();
//                    invOperateLine.setDeleted(true);
//                    invOperateLine.setType("2");
//                    invOperateLine.setGoodsName(orderLine.getScItemTitle());
//                    invOperateLine.setGoodsId(orderLine.getScItemId());
//
//                    LoadOrderListRequest loadOrderListRequest = new LoadOrderListRequest();
//                    loadOrderListRequest.setId(Long.valueOf(orderLine.getMainOrderId()));
//                    Result<List<Order>> orderListResult = orderService.loadOrderList(loadOrderListRequest);
//                    if (orderListResult != null && CollectionUtils.isNotEmpty(orderListResult.getResult())) {
//                        List<Order> orderList = orderListResult.getResult();
//                        Order order = orderList.get(0);
//                        //逻辑仓库id
//                        String wareHouseCode = order.getWareHouseCode();
//                        WmsSDO wmsSDO = InfoUtil.getWmsSDO(wareHouseCode);
//                        if (StringUtils.isBlank(wmsSDO.getWarehouseId())){
//                            //error
//                            throw new FacadeException("OTS-03-005-00-15-165");
//                        }
//                        invOperateLine.setWarehouseAreaId(wareHouseCode);
//                        invOperateLine.setWarehouseId(wmsSDO.getWarehouseId());
//                        invOperateLine.setReferenceOrderId(order.getId().toString());
//                        invOperateLine.setReferenceSubOrderId(orderLine.getId().toString());
//                        invOperateLine.setOutOrderId(datum.getDeliveryOrderId());
//                        invOperateLine.setOutSubOrderId(datum.getExt1().replaceAll(".",""));
//                        if (Objects.isNull(orderLine.getQuantity()) || orderLine.getQuantity() <= 0) {
//                            throw new FacadeException("OTS-03-005-00-15-167");
//                        }
//                        invOperateLine.setQuantity(String.valueOf(orderLine.getQuantity()*1000));
//                        invOperateLineList.add(invOperateLine);
//                    }
//                    occupyReleaseRequest.setInvOperateLineList(invOperateLineList);
//                    LOG.info("MnSapIf017ServiceImpl_salesOrderInvOccupy,occupyReleaseRequest:{}",JSON.toJSONString(occupyReleaseRequest));
//                    Result<OccupyReleaseResponse> occupyReleaseResponseResult = otsUnifiedInventoryService.occupyRelease(occupyReleaseRequest);
//                    if (occupyReleaseResponseResult == null || !occupyReleaseResponseResult.isSuccess()){
//                        //error
//                        throw new FacadeException("OTS-03-005-00-15-169");
//                    }
//                }
//
//            }
//
//
//
//
//            //017销售单预占库存逻辑
//            String outDeliveryOrderNo = datum.getDeliveryOrderId();
//            //销售单库存预占请求参数
//            OccupyRequest occupyRequest = new OccupyRequest();
//            //017销售单预占库存处理逻辑：
//            //查询017创建的交货单
//            //根据交货单中外部销售单号查销售单 确保该交货单绑定的是销售单据 调拨单不处理
//            //根据销售单号查交货单明细 明细信息封装释放、预占库存参数
//            ConsignmentOrderLoadListRequest consignmentOrderLoadListRequest = new ConsignmentOrderLoadListRequest();
//            consignmentOrderLoadListRequest.setOuterDeliveryOrderId(outDeliveryOrderNo);
//            Result<List<ConsignmentOrder>> loadConsignmentOrderListResult = consignmentOrderService.loadConsignmentOrderList(consignmentOrderLoadListRequest);
//            //交货单需要存在
//            if (loadConsignmentOrderListResult == null || CollectionUtils.isEmpty(loadConsignmentOrderListResult.getResult())){
//                throw new FacadeException("OTS-03-005-00-15-160");
//            }
//            ConsignmentOrder consignmentOrder = loadConsignmentOrderListResult.getResult().get(0);
//
//            //判断一下
//            String outerSalesOrderId = StringUtils.isNotBlank(consignmentOrder.getOuterSalesOrderId())?
//                    consignmentOrder.getOuterSalesOrderId() : consignmentOrder.getOuterStoOrderId();
//            //如果销售单存在查销售单
//            if (StringUtils.isBlank(outerSalesOrderId)){
//                throw new FacadeException("OTS-03-005-00-15-162");
//            }
//            LoadOrderListRequest loadOrderListRequest = new LoadOrderListRequest();
//            loadOrderListRequest.setOuterOrderId(outerSalesOrderId);
//            Result<List<Order>> orderListResult = orderService.loadOrderList(loadOrderListRequest);
//            //如果是销售单
//            if (orderListResult != null && CollectionUtils.isNotEmpty(orderListResult.getResult())){
//                List<Order> orderList = orderListResult.getResult();
//                Order order = orderList.get(0);
//                //逻辑仓库id
//                String wareHouseCode = order.getWareHouseCode();
//                //获取仓库档案id
//                //获取交货单明细
//                ConsignmentOrderLineLoadListRequest consignmentOrderLineLoadListRequest = new ConsignmentOrderLineLoadListRequest();
//                consignmentOrderLineLoadListRequest.setConsignmentOrderId(consignmentOrder.getId().toString());
//                Result<List<ConsignmentOrderLine>> listResult = consignmentOrderLineService.loadConsignmentOrderLineList(consignmentOrderLineLoadListRequest);
//                if (listResult != null && CollectionUtils.isNotEmpty(listResult.getResult())){
//                    //获取 outSOLineId - quantity 理论上行不会重复
//                    Map<String, List<ConsignmentOrderLine>> lineMap = listResult.getResult().stream().collect(Collectors.groupingBy(ConsignmentOrderLine::getOuterSoLineId));
//                    List<InvOperateLine> invOperateLineList = Lists.newArrayList();
//                    lineMap.forEach((k,v)->{
//                        //库存释放Request
//                        InvOperateLine invOperateLine = new InvOperateLine();
//
//                        if (CollectionUtils.isEmpty(v)){
//                            //error
//                            throw new FacadeException("OTS-03-005-00-15-163");
//                        }
//                        String scItemId = v.get(0).getScItemId();
//                        if (StringUtils.isBlank(scItemId)){
//                            //error
//                            throw new FacadeException("OTS-03-005-00-15-164");
//                        }
//                        invOperateLine.setGoodsId(scItemId);
//                        invOperateLine.setDeleted(false);
//                        invOperateLine.setType("2");
//                        invOperateLine.setOutOrderId(outDeliveryOrderNo);
//                        //发现没有时间戳 用交货单号代替了.
//                        invOperateLine.setOutSubOrderId(datum.getExt1());
//                        invOperateLine.setWarehouseAreaId(wareHouseCode);
//
//                        WmsSDO wmsSDO = InfoUtil.getWmsSDO(wareHouseCode);
//                        if (StringUtils.isBlank(wmsSDO.getWarehouseId())){
//                            //error
//                            throw new FacadeException("OTS-03-005-00-15-165");
//                        }
//                        invOperateLine.setWarehouseId(wmsSDO.getWarehouseId());
//                        invOperateLine.setReferenceOrderId(order.getId().toString());
//                        OrderLineLoadListRequest orderLineLoadListRequest = new OrderLineLoadListRequest();
//                        orderLineLoadListRequest.setMainOrderId(order.getId().toString());
//                        orderLineLoadListRequest.setOuterOrderLineId(k);
//                        Result<List<OrderLine>> lineResult = orderLineService.loadOrderLineList(orderLineLoadListRequest);
//                        if (lineResult == null || CollectionUtils.isEmpty(lineResult.getResult())){
//                            //error
//                            throw new FacadeException("OTS-03-005-00-15-166");
//                        }
//                        OrderLine orderLine = lineResult.getResult().get(0);
//                        invOperateLine.setReferenceSubOrderId(orderLine.getId().toString());
//                        Long quantity = v.stream().mapToLong(x -> {
//                            if (StringUtils.isBlank(x.getQty())) {
//                                return 0L;
//                            }
//                            BigDecimal bigDecimal = new BigDecimal(x.getQty().trim());
//                            return bigDecimal.movePointRight(3).longValue();
//                        }).sum();
//                        if (quantity <= 0 ){
//                            //error
//                            throw new FacadeException("OTS-03-005-00-15-167");
//                        }
//                        invOperateLine.setQuantity(quantity.toString());
//                        invOperateLineList.add(invOperateLine);
//                    });
//                    if (CollectionUtils.isEmpty(invOperateLineList)){
//                        //error
//                        throw new FacadeException("OTS-03-005-00-15-168");
//                    }
//                    occupyRequest.setInvOperateLineList(invOperateLineList);
//                    LOG.info("MnSapIf017ServiceImpl_salesOrderInvOccupy,request:{},occupyRequest:{}",JSON.toJSONString(outDeliveryOrderNo),JSON.toJSONString(occupyRequest));
//                    Result<OccupyResponse> occupyResponseResult = otsUnifiedInventoryService.occupy(occupyRequest);
//
//                    if (occupyResponseResult == null || !occupyResponseResult.isSuccess()){
//                        //error
//                        throw new FacadeException("OTS-03-005-00-15-169");
//                    }
//                }
//            }
//
//        return true;
//    }
    private boolean isNeedHandleOccupy(MnSapIf017SDO datum) {
        //新疆销售组织 不需要交货单处理预占
        if (strategyQueryAbility.avoidDeliveryOrderOccupy(datum.getSalesOrgId())){
            return false;
        }
        //013接口会同步特殊的销售单，判断ext=ZORO且销售组织是1171的交货单，修改为销售订单类型的交货单
        if ((StringUtils.isNotBlank(datum.getExt()) && saleOrderExtList.contains(datum.getExt())) && (
                StringUtils.isNotBlank(datum.getSalesOrgId()) && SPEC_ORG.equalsIgnoreCase(datum.getSalesOrgId())
        )) {
            return true;
        }
        //退货不预占库存
        if (returnGoodsExtList.contains(datum.getExt())) {
            return false;
        }
        //如果是换货的只接收换货的交货单号
        if (EXCHANGE_ORDER_TYPE.equals(datum.getExt())) {
            if (CollectionUtils.isNotEmpty(datum.getItems())) {
                boolean isExchange = datum.getItems().stream().anyMatch(x -> StringUtils.isNotBlank(x.getOuterSoLineId()) && Integer.valueOf(x.getOuterSoLineId().trim()) % 2 == 0);
                if (isExchange) {
                    return true;
                }
            }
            return false;
        }
        if (StringUtils.isNotBlank(datum.getSalesOrderId())) {
            return true;
        }

        return false;
    }

    //获取差异
    private Pair<OccupyRequest, OccupyReleaseRequest> getDiff(MnSapIf017SDO sdo, List<ConsignmentOrderLine> oldLines,
                                                              List<ConsignmentOrderLine> freshLines, List<OrderLine> orderLines,
                                                              boolean hasDelConsignmentOrder) {

        Pair<OccupyRequest, OccupyReleaseRequest> pair = null;
        //判断如果是交货单创建
        List<InvOperateLine> occupyInvOperateLineList = Lists.newArrayList();
//        OccupyOccupyReleaseRequest occupyReleaseRequest = new OccupyOccupyReleaseRequest();
        OccupyRequest occupyRequest = new OccupyRequest();
        OccupyReleaseRequest occupyReleaseRequest = new OccupyReleaseRequest();
        List<InvOperateLine> occupyReleaseInvOperateLineList = Lists.newArrayList();
        //TODO 013创建的销售单
        String salesOrderId = StringUtils.isNotBlank(sdo.getSalesOrderId()) ? sdo.getSalesOrderId() : sdo.getStoOrderId();
        String time = sdo.getExt1();
        String outDeliveryOrderNo = SapAndCrmFieldDealUtils.generateIdField(sdo.getDeliveryOrderId());
        LoadOrderListRequest loadOrderListRequest = new LoadOrderListRequest();
        loadOrderListRequest.setOuterOrderId(salesOrderId);
        Result<List<Order>> listResult = orderService.loadOrderList(loadOrderListRequest);
        if (listResult == null || CollectionUtils.isEmpty(listResult.getResult())) {
            throw new FacadeException("OTS-03-005-00-15-166");
        }
        Order order = listResult.getResult().get(0);
        String wareHouseCode = order.getWareHouseCode();
        WmsSDO wmsSDO = InfoUtil.getWmsSDO(wareHouseCode);
        if (StringUtils.isBlank(wmsSDO.getWarehouseId())) {
            //error
            log.error("MnSapIf017ServiceImpl_occupyRelease_Error,request:{},consignmentOrderLine:{}", JSON.toJSONString(outDeliveryOrderNo), JSON.toJSONString(wmsSDO));
            throw new FacadeException("OTS-03-005-00-15-165");
        }
        String warehouseId = wmsSDO.getWarehouseId();

        //要获取到预占的量 和释放的量
        if (CollectionUtils.isNotEmpty(orderLines) && !hasDelConsignmentOrder) {

            log.info("MnSapIf017V2ServiceImpl_occupyRelease_orderLines:{}", JSON.toJSONString(orderLines));
            //和原先的订单明细对比 需要注意换货的, 可以在开头进行排除
            for (ConsignmentOrderLine freshLine : freshLines) {
                List<OrderLine> sameLines = orderLines.stream().filter(x -> compare(freshLine.getOuterSoLineId(), x.getOuterOrderLineId()))
                        .collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(sameLines)) {
                    OrderLine orderLine = sameLines.get(0);
                    InvOperateLine invOperateLine = new InvOperateLine();
                    //判断qty和 basicQuantity的值是否相等 相等说明 和基本单位一样
                    BigDecimal unitConvert = getUnitConvert(freshLine.getBasicQuantity(), freshLine.getQty());
                    //如果转换是1
                    Long quantity;
                    Long reverseQuantity;
                    if (unitConvert.intValue() == 1) {
                        quantity = getDiff(orderLine.getQuantity(), freshLine.getBasicQuantity());
                        reverseQuantity = getDiff(freshLine.getBasicQuantity(), orderLine.getQuantity());
                    } else {
                        log.info("MnSapIf017V2ServiceImpl_occupyRelease_unit:{}", unitConvert.toString());
                        String oldQuantity = new BigDecimal(orderLine.getQuantity()).divide(unitConvert, 4, RoundingMode.HALF_UP)
                                .setScale(3, RoundingMode.HALF_UP).toString();
                        log.info("MnSapIf017V2ServiceImpl_occupyRelease_oldQuantity:{}", oldQuantity);
                        quantity = getDiffWithUnit(oldQuantity, freshLine.getBasicQuantity());
//                        quantity = getDiff(orderLine.getQuantity(),freshLine.getBasicQuantity());
                        reverseQuantity = getDiffWithUnit(freshLine.getBasicQuantity(), oldQuantity);
                    }
//                    Long quantity = getDiff(orderLine.getQuantity(), freshLine.getBasicQuantity());
//                    Long reverseQuantity = getDiff(freshLine.getBasicQuantity(), orderLine.getQuantity());
                    if (quantity > 0) {
                        invOperateLine.setQuantity(quantity.toString());
                        invOperateLine.setWarehouseId(warehouseId);
                        invOperateLine.setWarehouseAreaId(wareHouseCode);
                        invOperateLine.setType("2");
                        invOperateLine.setReferenceOrderId(order.getId().toString());
                        invOperateLine.setReferenceSubOrderId(orderLine.getId().toString());
                        invOperateLine.setOutOrderId(outDeliveryOrderNo);
                        invOperateLine.setOutSubOrderId(time);
                        invOperateLine.setDeleted(true);
                        invOperateLine.setGoodsId(orderLine.getScItemId());
                        occupyReleaseInvOperateLineList.add(invOperateLine);
                    } else if (quantity < 0) {
                        invOperateLine.setQuantity(reverseQuantity.toString());
                        invOperateLine.setWarehouseId(warehouseId);
                        invOperateLine.setWarehouseAreaId(wareHouseCode);
                        invOperateLine.setType("2");
                        invOperateLine.setReferenceOrderId(order.getId().toString());
                        invOperateLine.setReferenceSubOrderId(orderLine.getId().toString());
                        invOperateLine.setOutOrderId(outDeliveryOrderNo);
                        invOperateLine.setOutSubOrderId(time + SPLIT + orderLine.getId());
                        invOperateLine.setDeleted(false);
                        invOperateLine.setGoodsId(orderLine.getScItemId());
                        occupyInvOperateLineList.add(invOperateLine);
                    } else {
                        continue;
                    }
                }
            }
            //这里不需要反向比较,删除的时候 会释放预占 orderLine里需要去掉行关闭的

        } else if (CollectionUtils.isNotEmpty(oldLines)) {
            log.info("MnSapIf017V2ServiceImpl_occupyRelease_oldLines:{}", JSON.toJSONString(oldLines));
            //获取 新交货单和老交货单的差异
            for (ConsignmentOrderLine freshLine : freshLines) {
                List<ConsignmentOrderLine> sameLines = oldLines.stream().filter(x -> Objects.equals(SapAndCrmFieldDealUtils.generateIdField(x.getOuterSoLineId()),
                        SapAndCrmFieldDealUtils.generateIdField(freshLine.getOuterSoLineId()))).collect(Collectors.toList());
                //行相同 比较数量
                if (CollectionUtils.isNotEmpty(sameLines)) {
                    ConsignmentOrderLine consignmentOrderLine = sameLines.get(0);
                    InvOperateLine invOperateLine = new InvOperateLine();
                    Long quantity = getDiff(consignmentOrderLine.getBasicQuantity(), freshLine.getBasicQuantity());
                    Long reverseQuantity = getDiff(freshLine.getBasicQuantity(), consignmentOrderLine.getBasicQuantity());
                    if (quantity > 0) {
                        OrderLineLoadListRequest orderLineLoadListRequest = new OrderLineLoadListRequest();
                        orderLineLoadListRequest.setOuterOrderLineId(SapAndCrmFieldDealUtils.generateIdField(freshLine.getOuterSoLineId()));
                        orderLineLoadListRequest.setMainOrderId(order.getId().toString());
                        Result<List<OrderLine>> orderLineList = orderLineService.loadOrderLineList(orderLineLoadListRequest);
                        if (orderLineList == null || CollectionUtils.isEmpty(orderLineList.getResult())) {
                            log.error("MnSapIf018ServiceImpl_occupyRelease_Error,request:{},consignmentOrderLine:{}", JSON.toJSONString(outDeliveryOrderNo), JSON.toJSONString(orderLineLoadListRequest));
                            throw new FacadeException("OTS-03-005-00-15-166");
                        }
                        OrderLine orderLine = orderLineList.getResult().get(0);
                        invOperateLine.setQuantity(quantity.toString());
                        invOperateLine.setWarehouseId(warehouseId);
                        invOperateLine.setWarehouseAreaId(wareHouseCode);
                        invOperateLine.setType("2");
                        invOperateLine.setReferenceOrderId(order.getId().toString());
                        invOperateLine.setReferenceSubOrderId(orderLine.getId().toString());
                        invOperateLine.setOutOrderId(outDeliveryOrderNo);
                        invOperateLine.setOutSubOrderId(time);
                        invOperateLine.setDeleted(false);
                        String scItemId = orderLine.getScItemId();
                        if (StringUtils.isBlank(scItemId)) {
                            //error
                            log.error("MnSapIf018ServiceImpl_occupyRelease_Error,request:{},consignmentOrderLine:{}", JSON.toJSONString(outDeliveryOrderNo), JSON.toJSONString(orderLine));
                            throw new FacadeException("OTS-03-005-00-15-164");
                        }
                        invOperateLine.setGoodsId(scItemId);
                        occupyInvOperateLineList.add(invOperateLine);
                    } else if (quantity < 0) {
                        OrderLineLoadListRequest orderLineLoadListRequest = new OrderLineLoadListRequest();
                        orderLineLoadListRequest.setOuterOrderLineId(SapAndCrmFieldDealUtils.generateIdField(freshLine.getOuterSoLineId()));
                        orderLineLoadListRequest.setMainOrderId(order.getId().toString());
                        Result<List<OrderLine>> orderLineList = orderLineService.loadOrderLineList(orderLineLoadListRequest);
                        if (orderLineList == null || CollectionUtils.isNotEmpty(orderLines)) {
                            log.error("MnSapIf018ServiceImpl_occupyRelease_Error,request:{},consignmentOrderLine:{}", JSON.toJSONString(outDeliveryOrderNo), JSON.toJSONString(orderLines));
                            throw new FacadeException("OTS-03-005-00-15-166");
                        }
                        OrderLine orderLine = orderLineList.getResult().get(0);
                        invOperateLine.setQuantity(reverseQuantity.toString());
                        invOperateLine.setWarehouseId(warehouseId);
                        invOperateLine.setWarehouseAreaId(wareHouseCode);
                        invOperateLine.setType("2");
                        invOperateLine.setReferenceOrderId(order.getId().toString());
                        invOperateLine.setReferenceSubOrderId(orderLine.getId().toString());
                        invOperateLine.setOutOrderId(outDeliveryOrderNo);
//                        invOperateLine.setOutSubOrderId(time);
                        invOperateLine.setOutSubOrderId(time + SPLIT + orderLine.getId());
                        invOperateLine.setDeleted(true);
                        String scItemId = consignmentOrderLine.getScItemId();
                        if (StringUtils.isBlank(scItemId)) {
                            log.error("MnSapIf018ServiceImpl_occupyRelease_Error,request:{},consignmentOrderLine:{}", JSON.toJSONString(outDeliveryOrderNo), JSON.toJSONString(consignmentOrderLine));
                            throw new FacadeException("OTS-03-005-00-15-164");
                        }
                        invOperateLine.setGoodsId(scItemId);
                        occupyReleaseInvOperateLineList.add(invOperateLine);
                    } else {
                        continue;
                    }


                } else {
                    log.info("MnSapIf018V2ServiceImpl_Line_add:{}", JSON.toJSONString(freshLine));
                    //如果没有这行 需要释放
                    InvOperateLine invOperateLine = new InvOperateLine();
                    OrderLineLoadListRequest orderLineLoadListRequest = new OrderLineLoadListRequest();
                    orderLineLoadListRequest.setOuterOrderLineId(SapAndCrmFieldDealUtils.generateIdField(freshLine.getOuterSoLineId()));
                    orderLineLoadListRequest.setMainOrderId(order.getId().toString());
                    Result<List<OrderLine>> orderLineList = orderLineService.loadOrderLineList(orderLineLoadListRequest);
                    if (orderLineList == null || CollectionUtils.isEmpty(orderLineList.getResult())) {
                        log.error("MnSapIf018ServiceImpl_occupyRelease_Error,request:{},consignmentOrderLine:{}", JSON.toJSONString(outDeliveryOrderNo), JSON.toJSONString(orderLineLoadListRequest));
                        throw new FacadeException("OTS-03-005-00-15-166");
                    }
                    OrderLine orderLine = orderLineList.getResult().get(0);
                    String basicQuantity = freshLine.getBasicQuantity();
                    Long quantity;
                    if (StringUtils.isBlank(basicQuantity)) {
                        quantity = 0L;
                    } else {
                        quantity = new BigDecimal(basicQuantity.trim()).movePointRight(3).longValue();
                    }
                    if (quantity <= 0) {
                        log.error("MnSapIf017ServiceImpl_occupyRelease_Error,request:{},consignmentOrderLine:{}", JSON.toJSONString(outDeliveryOrderNo), JSON.toJSONString(freshLine));
                        throw new FacadeException("OTS-03-005-00-15-167");
                    }
                    invOperateLine.setQuantity(quantity.toString());
                    invOperateLine.setWarehouseId(warehouseId);
                    invOperateLine.setWarehouseAreaId(wareHouseCode);
                    invOperateLine.setType("2");
                    invOperateLine.setReferenceOrderId(order.getId().toString());
                    invOperateLine.setReferenceSubOrderId(orderLine.getId().toString());
                    invOperateLine.setOutOrderId(outDeliveryOrderNo);
                    invOperateLine.setOutSubOrderId(time);
                    invOperateLine.setDeleted(false);
                    String scItemId = orderLine.getScItemId();
                    if (StringUtils.isBlank(scItemId)) {
                        //error
                        log.error("MnSapIf018ServiceImpl_occupyRelease_Error,request:{},consignmentOrderLine:{}", JSON.toJSONString(outDeliveryOrderNo), JSON.toJSONString(orderLine));
                        throw new FacadeException("OTS-03-005-00-15-164");
                    }
                    invOperateLine.setGoodsId(scItemId);
                    occupyInvOperateLineList.add(invOperateLine);
                }
            }
            //
            for (ConsignmentOrderLine oldLine : oldLines) {
                List<ConsignmentOrderLine> sameLines = freshLines.stream().filter(x -> Objects.equals(SapAndCrmFieldDealUtils.generateIdField(x.getOuterSoLineId()),
                        SapAndCrmFieldDealUtils.generateIdField(oldLine.getOuterSoLineId()))).collect(Collectors.toList());
                //即需要释放这行 重复的已经在上面处理了   老的234  新的345
                if (CollectionUtils.isEmpty(sameLines)) {

                    InvOperateLine invOperateLine = new InvOperateLine();
                    OrderLineLoadListRequest orderLineLoadListRequest = new OrderLineLoadListRequest();
                    orderLineLoadListRequest.setMainOrderId(order.getId().toString());
                    orderLineLoadListRequest.setOuterOrderLineId(SapAndCrmFieldDealUtils.generateIdField(oldLine.getOuterSoLineId()));
                    Result<List<OrderLine>> orderLineList = orderLineService.loadOrderLineList(orderLineLoadListRequest);
                    if (orderLineList == null || CollectionUtils.isEmpty(orderLineList.getResult())) {
                        log.error("MnSapIf018ServiceImpl_occupyRelease_Error,request:{},consignmentOrderLine:{}", JSON.toJSONString(outDeliveryOrderNo), JSON.toJSONString(orderLineLoadListRequest));
                        throw new FacadeException("OTS-03-005-00-15-166");
                    }
                    OrderLine orderLine = orderLineList.getResult().get(0);
                    String basicQuantity = oldLine.getBasicQuantity();
                    Long quantity;
                    if (StringUtils.isBlank(basicQuantity)) {
                        quantity = 0L;
                    } else {
                        quantity = new BigDecimal(basicQuantity.trim()).movePointRight(3).longValue();
                    }
                    if (quantity <= 0) {
                        log.error("MnSapIf017ServiceImpl_occupyRelease_Error,request:{},consignmentOrderLine:{}", JSON.toJSONString(outDeliveryOrderNo), JSON.toJSONString(orderLine));
                        throw new FacadeException("OTS-03-005-00-15-167");
                    }
                    invOperateLine.setQuantity(quantity.toString());
                    invOperateLine.setWarehouseId(warehouseId);
                    invOperateLine.setWarehouseAreaId(wareHouseCode);
                    invOperateLine.setType("2");
                    invOperateLine.setReferenceSubOrderId(orderLine.getId().toString());
                    invOperateLine.setReferenceOrderId(order.getId().toString());
                    invOperateLine.setOutOrderId(outDeliveryOrderNo);
                    invOperateLine.setDeleted(true);
                    String scItemId = orderLine.getScItemId();
                    if (StringUtils.isBlank(scItemId)) {
                        //error
                        log.error("MnSapIf018ServiceImpl_occupyRelease_Error,request:{},consignmentOrderLine:{}", JSON.toJSONString(outDeliveryOrderNo), JSON.toJSONString(orderLine));
                        throw new FacadeException("OTS-03-005-00-15-164");
                    }
                    invOperateLine.setGoodsId(scItemId);
                    occupyReleaseInvOperateLineList.add(invOperateLine);
                }
            }
        } else if (CollectionUtils.isEmpty(oldLines) && hasDelConsignmentOrder) {
            log.info("MnSapIf018ServiceImpl_occupyRelease_ConsignmentOrder_hasDel:{}", JSON.toJSONString(outDeliveryOrderNo));
            //如果交货单删除后,又来了新的交货单 那么就需要重新预占改交货单了.
            for (ConsignmentOrderLine freshLine : freshLines) {
                OrderLineLoadListRequest orderLineLoadListRequest = new OrderLineLoadListRequest();
                orderLineLoadListRequest.setOuterOrderLineId(SapAndCrmFieldDealUtils.generateIdField(freshLine.getOuterSoLineId()));
                orderLineLoadListRequest.setMainOrderId(order.getId().toString());
                Result<List<OrderLine>> orderLineList = orderLineService.loadOrderLineList(orderLineLoadListRequest);
                if (orderLineList == null || CollectionUtils.isEmpty(orderLineList.getResult())) {
                    log.error("MnSapIf018ServiceImpl_occupyRelease_Error,request:{},consignmentOrderLine:{}", JSON.toJSONString(outDeliveryOrderNo), JSON.toJSONString(orderLineLoadListRequest));
                    throw new FacadeException("OTS-03-005-00-15-166");
                }
                InvOperateLine invOperateLine = new InvOperateLine();
                OrderLine orderLine = orderLineList.getResult().get(0);
                invOperateLine.setQuantity(new BigDecimal(freshLine.getBasicQuantity().trim()).movePointRight(3).toString());
                invOperateLine.setWarehouseId(warehouseId);
                invOperateLine.setWarehouseAreaId(wareHouseCode);
                invOperateLine.setType("2");
                invOperateLine.setReferenceOrderId(order.getId().toString());
                invOperateLine.setReferenceSubOrderId(orderLine.getId().toString());
                invOperateLine.setOutOrderId(outDeliveryOrderNo);
                invOperateLine.setOutSubOrderId(time);
                invOperateLine.setDeleted(false);
                String scItemId = orderLine.getScItemId();
                if (StringUtils.isBlank(scItemId)) {
                    //error
                    log.error("MnSapIf018ServiceImpl_occupyRelease_Error,request:{},consignmentOrderLine:{}", JSON.toJSONString(outDeliveryOrderNo), JSON.toJSONString(orderLine));
                    throw new FacadeException("OTS-03-005-00-15-164");
                }
                invOperateLine.setGoodsId(scItemId);
                occupyInvOperateLineList.add(invOperateLine);
            }
        }
        if (CollectionUtils.isNotEmpty(occupyInvOperateLineList) || CollectionUtils.isNotEmpty(occupyReleaseInvOperateLineList)) {
            occupyRequest.setInvOperateLineList(occupyInvOperateLineList);
            occupyReleaseRequest.setInvOperateLineList(occupyReleaseInvOperateLineList);
            return Pair.of(occupyRequest, occupyReleaseRequest);
        }
        return null;
    }

    private static boolean isEqualNumber(String old, String fresh) {
        BigDecimal oldBigDecimal = new BigDecimal(old.trim()).movePointRight(3);
        BigDecimal freshBigDecimal = new BigDecimal(fresh.trim()).movePointRight(3);
        return oldBigDecimal.longValue() == freshBigDecimal.longValue();
    }

    private static Long getDiff(String old, String fresh) {
        BigDecimal oldBigDecimal = new BigDecimal(old.trim()).movePointRight(3);
        BigDecimal freshBigDecimal = new BigDecimal(fresh.trim()).movePointRight(3);
        return freshBigDecimal.subtract(oldBigDecimal).longValue();
    }

    private static Long getDiff(Integer old, String fresh) {
        if (old == null) {
            old = 0;
        }
        BigDecimal bigDecimal = new BigDecimal(old).movePointRight(3);
        BigDecimal decimal = new BigDecimal(fresh.trim()).movePointRight(3);
        return bigDecimal.subtract(decimal).longValue();
    }

    private static Long getDiffWithUnit(String old, String fresh) {
        BigDecimal bigDecimal = new BigDecimal(old.trim()).movePointRight(3);
        BigDecimal decimal = new BigDecimal(fresh.trim()).movePointRight(3);
        return bigDecimal.subtract(decimal).longValue();
    }

    private static Long getDiff(String fresh, Integer old) {
        if (old == null) {
            old = 0;
        }
        BigDecimal bigDecimal = new BigDecimal(old).movePointRight(3);
        BigDecimal decimal = new BigDecimal(fresh.trim()).movePointRight(3);
        return decimal.subtract(bigDecimal).longValue();
    }

    private static boolean compare(String oldLineId, String freshLineId) {
        return Objects.equals(SapAndCrmFieldDealUtils.generateIdField(oldLineId),
                SapAndCrmFieldDealUtils.generateIdField(freshLineId));
    }

    //获取转换关系
    private static BigDecimal getUnitConvert(String basicQuantity, String qty) {
        BigDecimal basicBigDecimal = BigDecimal.ZERO;
        BigDecimal qtyBigDecimal = BigDecimal.ZERO;
        if (StringUtils.isNotBlank(basicQuantity)) {
            basicBigDecimal = new BigDecimal(basicQuantity.trim());
        }
        if (StringUtils.isNotBlank(qty)) {
            qtyBigDecimal = new BigDecimal(qty.trim());
        }
        return qtyBigDecimal.divide(basicBigDecimal, 5, RoundingMode.HALF_UP);
    }

}
